7

我试图弄清楚为什么在包含括号时以下代码会导致堆栈溢出,但在省略括号时却不会。

我将函数本身作为 setTimeout 的参数调用,它可以在没有括号的情况下工作,但是当我添加它们时当然会失败。我的直觉是在函数后面加上 ()。只是希望有人可以为我解决这个问题。什么时候参数是可选的而不是?

情况1:

var a = 1;

function foo() {
    a++;
    document.write(a);
    setTimeout(foo(), 2000)
}​ 
// RangeError: Maximum call stack size exceeded

案例二:

var a = 1;

function foo() {
    a++;
    document.write(a);
    setTimeout(foo, 2000)
}​
// parens are omitted on foo function and it works. 
4

2 回答 2

12

这个问题通常首先参考 被问到setTimeout,但我认为重要的是要指出这里的行为并不特定于该函数。您只需要了解括号的作用以及不使用括号的含义。

假设以下函数:

function foo() {
    return 5;
}

考虑以下两个变量声明/赋值:

var one = foo();
var two = foo;

这些变量有什么值?

在第一种情况下,我们正在执行函数foo并将其返回值——数字5——分配给one. 在第二种情况下,我们将自己分配给——foo更准确地说,是对 的引用。该函数永远不会执行。footwo

有了这些知识和理解,setTimeout它的第一个参数是对函数的引用,你的第一个案例失败的原因应该很明显,但第二个案例有效。

当然,您正在执行的函数是对自身的递归调用,这一事实加剧了您的问题。这将永远运行——对于永远的定义——因为没有终止递归的基本情况。

于 2012-07-09T21:37:35.287 回答
9

通过写作

foo()

那时你实际上是在打电话给 foo 。当然,然后再次调用 foo() ......直到你stackoverflow。

在案例 2 中,您有效地将“引用”传递给 foo,说“在 2 秒内运行它”。实际上没有调用 foo()。

因此,当您真正想要调用它时,请使用括号。不是当你想引用它时。

于 2012-07-09T21:23:43.087 回答