最近,我一直在阅读有关Github的《不懂JS》系列书籍,其中的一小段代码确实使我难以理解。我简化了代码,并在下面为您介绍了两种不同版本的代码:
正确的版本:
var fun = function () {
console.log("this is something");
}
var func = fun; // why this line?
fun = function() {
func.call(null);
}
fun();
版本错误:
var fun = function () {
console.log("this is something");
}
fun = function() {
fun.call(null); // why this causes error?
}
fun();
如果您运行第二个代码段,则会出现错误“超出最大调用堆栈大小”。
我不明白为什么摘要1中的行var func = fun;
是必需的。
答案 0 :(得分:5)
fun = function() {
fun.call(null);
}
fun();
您有一个函数可以调用fun
中存储的任何内容,并将其分配给fun
。那只是无限递归。
其余代码无关紧要。特别是,fun
的旧值在分配fun = ...
被覆盖之前从未使用过。
第一个示例的不同之处在于,func
永远不会被覆盖,因此它仍然保留对第一个函数的引用,该函数仅调用console.log
。
换句话说,在第一种情况下,呼叫链一直存在
fun --> func --> console.log
带有fun = function () { func.call(null) }
和func = function () { console.log("this is something") }
,
在第二种情况下会发生
fun --> fun --> fun --> fun --> ...
带有fun = function () { fun.call(null) }
。
这里至关重要的是function() { fun.call(null); }
不会捕获fun
的副本。可以这么说,这并不是说fun
的值在定义函数时就被冻结了。
相反,函数捕获变量本身(而不是它在某个时刻具有的值)。这就是为什么在调用函数时,它将使用调用时存储在fun
中的任何值。
该问题的简化演示:
var x = "hello";
var f = function () {
console.log(x);
};
x = "bye";
f();
此代码显示bye
,而不是hello
。