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

时间:2014-01-06 02:36:00

标签: javascript ecmascript-5 name-binding

考虑以下命名函数:

function f() {
    return f.apply(this, arguments);
}

如果正常调用此函数,则会导致堆栈溢出,如预期的那样。不是很有趣。让我们做一些魔术:

var g = f, f = alert;

现在,如果你致电f,它只会alert第一个参数。但是,如果您致电g,它仍然会alert第一个参数。发生了什么?不应该调用g会导致堆栈溢出吗?

我理解的是,在函数f(现在为g)内,变量f不再绑定到f。它变成了一个自由变量。因此,在f内,变量f现在指向alert

为什么会这样?我希望命名函数中的函数名始终引用函数本身。我没有抱怨。它真的很酷。我只是好奇。

2 个答案:

答案 0 :(得分:4)

当你这样做时:

var g = f

这实际上与:

相同
var g = function () {
    return f.apply(this, arguments);
}

但是,由于您重新分配了f,它不再指向原始函数,现在它指向alert。看起来它按设计工作。

答案 1 :(得分:1)

如其他答案所述,它是按照设计的。基本上,除了吊装之外,声明是这样做的:

var f = function () {
    return f.apply(this, arguments);
}

也就是说,f的值未在声明处解析,而是在函数调用期间解析。这就是为什么你会看到你所看到的。

但是有一种方法可以强制它按照你想要的方式行事:使用named function expression。命名函数表达式看起来像声明,但不是由于函数被声明为表达式。

例如,在以下内容中:

var ff = function f () {
    return f.apply(this, arguments);
}

f的值在声明中受到约束,并且不受重新分配的影响。在命名函数表达式中,函数名仅在表达式中定义,因此更像是闭包而不是变量。