请考虑以下命名函数:
function f() {
return f.apply(this, arguments);
}
如果正常调用此函数,则会导致堆栈按预期溢出。不是很有趣。所以让我们做一些魔法:
var g = f, f = alert;
现在,如果您调用f
它将简单地alert
第一个参数。但是,如果您调用g
它仍将alert
第一个参数。发生了什么事情?调用g
不应该导致堆栈溢出吗?
我的理解是,在函数f
(现在g
)内部,变量f
不再绑定到f
。它成为一个自由变量。因此,在f
内部,变量f
现在指向alert
。
为什么会这样?我希望命名函数中的函数名称始终引用函数本身。我不是在抱怨。这实际上很酷。我只是好奇。
当你这样做时:
var g = f
这实际上与以下相同:
var g = function () {
return f.apply(this, arguments);
}
但是,由于您重新分配了f
它不再指向原始函数,它现在指向 alert
。看起来它正在按设计工作。
正如其他答案所提到的,它是设计好的。基本上,除了吊装,声明是这样做的:
var f = function () {
return f.apply(this, arguments);
}
也就是说,f
的值不是在声明中解析的,而是在函数调用期间解析的。这就是为什么你看到你所看到的。
但是有一种方法可以强制它按照您想要的方式运行:使用命名函数表达式。命名函数表达式看起来像声明,但不是由于函数被声明为表达式。
例如,在以下方面:
var ff = function f () {
return f.apply(this, arguments);
}
f
的价值在声明时受约束,并且不受重新分配的影响。在命名函数表达式中,函数名称仅在表达式内部定义,因此行为更像是闭包而不是变量。