setTimeout回调参数

20

让我们考虑这段 JavaScript 代码:

function Person(name) {
    this.name = name;
}

Person.prototype.showName = function() {
    alert(this.name);
}


var mike = new Person("mike");
//mike.showName();  

window.name = "window"; 
我不理解以下两个代码片段的区别:

setTimeout(mike.showName(), 5000);

setTimeout(function(){
    mike.showName();
}, 5000);

为什么行为不同?这真的让我困惑。谢谢。


5
我相当确定OP在说“performance”时是指“行为”。 - Wayne
4个回答

67

你的问题与 setTimeout 完全没有任何关系。你只需要理解函数调用和对函数的引用之间的区别。

考虑以下四个赋值:

var one = function() { mike.showName(); };
var two = mike.showName;
var three = mike.showName();
var four = (function() { mike.showName(); })();

前两个将函数的引用赋值给它们各自的变量。然而,后两个却调用函数(这就是括号的作用),并将它们的返回值分配给左侧的变量。

这与 setTimeout 的关系:

setTimeout 函数期望它的第一个参数是一个指向函数的引用,因此上述的onetwo都是正确的,而threefour则不行。然而,需要注意的是,将函数的返回值传递给setTimeout 并不是严格意义上的错误,尽管你会经常看到这样的说法。

例如,下面这种写法完全没问题:

function makeTimeoutFunc(param) {
    return function() {
        // does something with param
    }
}

setTimeout(makeTimeoutFunc(), 5000);

这与setTimeout如何接收函数作为参数无关,而是与它确实接收有关。


2
非常感谢你,你的回答很棒。然而我还有一个疑惑。你能告诉我为什么'mike.showName()'会先执行,而'function(){ mike.showName()}'要等待5秒钟吗?再次感谢。 - jsnewman
5
дә йЂ’mike.showName()иҰЁз¤ғз«‹еҚіиүђиҰЊе‡Ңж•°showName并将其иү”е›һеЂәдҢњдёғе›һи°ѓдә йЂ’пәЊдҢ†ењЁ5з§’й’џеђҺдёҚдәљж‰§иҰЊд»»дҢ•ж“ҚдҢњгЂ‚然而пәЊдә йЂ’function(){ mike.showName() }дәљеђ‘setTimeoutжЏђдң›дёЂдёҒеЊүеђҚе‡Ңж•°пәЊењЁ5з§’й’џеђҺиүђиҰЊгЂ‚дғ”з§’й’џиү‡еҺ»дғ†пәЊе¤–йѓЁеЊ…иӘ…е‡Ңж•°иұ«ж‰§иҰЊгЂ‚е®ѓеЊ…еђ«дёЂиҰЊд»Әз ЃпәЊеҚіеҮ№showNameзљ„и°ѓз”ЁпәЊиҮӨ调用在此时执иҰЊгЂ‚ - Wayne

27

如果被接受的答案太长难以阅读:

setTimeout(mike.showName(), 5000);

这将在5,000毫秒后执行mike.showName()返回的任何内容。

setTimeout(function(){ mike.showName(); }, 5000);

这将在5000毫秒后执行匿名函数,该函数调用mike.showName(),即实际函数

另一种实现相同效果的方法:

setTimeout(mike.showName.bind(mike), 5000);

10

这不是性能问题。你展示的其中一种方式根本行不通(它会立刻调用该函数而不是在超时后执行)。

setTimeout(mike.showName(), 5000);执行了showName函数并将其返回值设置为超时回调,这样是行不通的。

setTimeout(function(){ mike.showName(); }, 5000);创建一个匿名函数并将其设为超时回调。当超时触发时,该函数会被调用并调用您的showName()函数。

请注意:setTimeout('mike.showName();', 5000);也可以工作。但不要这样做——它和使用eval()一样糟糕。此外,由于字符串中的代码无法语法突出显示,所以它使您的代码难以阅读。


你能告诉我为什么'mike.showName()'会先执行,而'function(){ mike.showName()}'则要等待它的时间吗?非常感谢。 - jsnewman
因为你实际上在那一行调用了该函数。如果你将其包装在匿名函数中或者只是传递函数而不使用 () 调用它,那么它就不会被调用 - 只有函数本身被传递。 - ThiefMaster

6

setTimeout(mike.showName(), 5000); 立即执行 mike.showName() 并将返回值传递给 setTimeout()

setTimeout(function(){ mike.showName(); }, 5000); 则传递函数的指针而不是返回值。这样,setTimeout 可以执行该函数而非其返回值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接