2012-07-09 77 views
6

我想包装我的头,为什么下面的代码导致堆栈溢出时,括号中包括,但不要当他们省略。为什么在传递函数作为参数时必须省略括号?

我打电话给函数本身作为setTimeout的一个参数,它工作时没有parantheses,但是当我添加它们的时候失败了。在函数后面添加()是我的直觉。只希望有人能为我解决这个问题。什么时候可以选择而不是?

案例1:

var a = 1; 

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

案例2:

var a = 1; 

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

可能是dup。这应该有所帮助:http://stackoverflow.com/questions/5520155/settimeout-callback-argument/5520190#5520190 – 2012-07-09 21:25:58

+0

非常感谢你lwburk,你在该链接的解释清除了我的东西。 – 2012-07-09 21:44:32

回答

9

这个问题通常首先要求参考setTimeout,但我认为指出这里的行为不是特定于该函数是很重要的。你只需要理解括号的作用,以及它的意思。

假设以下功能:

function foo() { 
    return 5; 
} 

考虑以下两个变量声明/分配:

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

做这些变量有什么样的价值观?

在第一种情况下,我们是执行foo功能和分配它的返回值 - 数5 - 到one。在第二种情况下,我们将foo本身 - 更确切地说是指foo - 指定为two。该功能从未执行。

有了这些知识和setTimeout预计作为其第一个参数参考的功能的理解,它应该是显而易见的,为什么你的第一个案例失败,但第二个作品。

当然,您正在执行的函数是对其自身的递归调用,您的问题会加剧。这将永远运行 - 永久的定义 - 因为没有基本的情况来终止递归。

+0

优秀的答案,谢谢。 – 2012-07-09 21:49:11

+0

我现在必须问,如果你想用参数引用foo函数呢?例如setTimeout(foo(x),2000)。我现在明白,这显然会导致堆栈溢出,但可以在第一个函数引用中传递参数吗? – 2012-07-09 21:55:07

+0

@ChrisM - 是的,在这种情况下,最好的做法是将引用传递给匿名函数,然后调用所需的函数。像这样:'setTimeout(function(){foo(x)},2000)' – 2012-07-09 21:56:28

9

通过编写

foo() 

你实际上在那一刻调用foo。当然哪个当然再次调用foo()...直到你达到stackoverflow。

在情况2中,您有效地将“参考”传递给foo,并说“以2s运行”。实际上并没有调用foo()。

所以,当你真的想要调用它的时候使用parens。不是当你想参考它。

+0

作为一个例子,尝试在控制台中运行var foo =(function(){alert(“Hello”);})';然后,尝试运行'var foo =(function(){alert(“Hello”);})()' - 注意声明结尾处的parens如何在定义后立即调用函数! – 2012-07-09 21:26:00

+0

这对我来说非常合理。我将setTimeout(x,y)的两个参数解释为x =你想要做什么,y =你想多久执行一次。为了我的误解,我想调用并执行foo,并每2秒执行一次。感谢您的回答! – 2012-07-09 21:46:45

相关问题