为什么需要将函数引用保存到变量的语句?

时间:2019-06-20 12:09:59

标签: javascript

最近,我一直在阅读有关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;是必需的。

1 个答案:

答案 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