为什么 JavaScript 中命名函数内的函数名称不再引用函数本身



请考虑以下命名函数:

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的价值在声明时受约束,并且不受重新分配的影响。在命名函数表达式中,函数名称仅在表达式内部定义,因此行为更像是闭包而不是变量。

最新更新