如何将参数传递给 setTimeout()回调?

function statechangedPostQuestion()
{
  //alert("statechangedPostQuestion");
  if (xmlhttp.readyState==4)
  {
    var topicId = xmlhttp.responseText;
    setTimeout("postinsql(topicId)",4000);
  }
}

function postinsql(topicId)
{
  //alert(topicId);
}

答案

setTimeout(function() {
    postinsql(topicId);
}, 4000)

您需要将匿名函数作为参数而不是字符串作为参数,后一种方法甚至不符合 ECMAScript 规范,但浏览器比较宽松。这是正确的解决方案,在使用setTimeout()setInterval() ,永远不要依赖于将字符串作为 “函数” 传递,它速度较慢,因为必须对其进行评估,而且这样做是不对的。

更新:

正如 Hobblin 在对问题的评论中所说,现在您可以使用Function.prototype.bind()将参数传递给 setTimeout 内部的Function.prototype.bind()

例:

setTimeout(postinsql.bind(null, topicId), 4000);

在现代浏览器中,“setTimeout” 接收第三个参数,该参数在计时器结束时作为参数发送到内部函数。

例:

var hello = "Hello World";
setTimeout(alert, 1000, hello);

更多细节:

经过一些研究和测试,唯一正确的实现是:

setTimeout(yourFunctionReference, 4000, param1, param2, paramN);

setTimeout 会将所有其他参数传递给您的函数,以便可以在此处进行处理。

匿名函数可以用于非常基本的东西,但是在必须使用 “this” 的对象实例中,没有办法使其起作用。任何匿名函数都会将 “this” 更改为指向窗口,因此您将丢失对象引用。

这是一个非常老的问题,已经有了 “正确” 的答案,但我想我想提到的是这里没有人提及的另一种方法。这是从出色的下划线库复制并粘贴的:

_.delay = function(func, wait) {
  var args = slice.call(arguments, 2);
  return setTimeout(function(){ return func.apply(null, args); }, wait);
};

您可以将任意数量的参数传递给 setTimeout 调用的函数, 并且作为附加的奖励(通常是奖励),调用 setTimeout 时,传递给函数的参数的值将被冻结,因此,如果它们改变了值在 setTimeout()被调用和它超时之间的某个时间点,好吧... 这不再那么令人沮丧了:)

这是一个小提琴 ,在这里您可以了解我的意思。

最近,我遇到了需要在循环中使用setTimeout的特殊情况。了解这一点可以帮助您了解如何将参数传递给setTimeout

方法 1

根据 Sukima 的建议 ,使用forEachObject.keys

var testObject = {
    prop1: 'test1',
    prop2: 'test2',
    prop3: 'test3'
};

Object.keys(testObject).forEach(function(propertyName, i) {
    setTimeout(function() {
        console.log(testObject[propertyName]);
    }, i * 1000);
});

我推荐这种方法。

方法二

使用bind

var i = 0;
for (var propertyName in testObject) {
    setTimeout(function(propertyName) {
        console.log(testObject[propertyName]);
    }.bind(this, propertyName), i++ * 1000);
}

JSFiddle: http : //jsfiddle.net/MsBkW/

方法 3

或者,如果您不能使用forEachbind ,请使用IIFE

var i = 0;
for (var propertyName in testObject) {
    setTimeout((function(propertyName) {
        return function() {
            console.log(testObject[propertyName]);
        };
    })(propertyName), i++ * 1000);
}

方法 4

但是,如果您不关心 IE <10,则可以使用 Fabio 的建议

var i = 0;
for (var propertyName in testObject) {
    setTimeout(function(propertyName) {
        console.log(testObject[propertyName]);
    }, i++ * 1000, propertyName);
}

方法 5(ES6)

使用块范围的变量:

let i = 0;
for (let propertyName in testObject) {
    setTimeout(() => console.log(testObject[propertyName]), i++ * 1000);
}

尽管我仍然建议在 ES6 中将Object.keysforEach使用。

霍布林已经对这个问题发表了评论,但它确实应该是一个答案!

使用Function.prototype.bind()是最干净,最灵活的方法(具有设置this上下文的额外好处):

setTimeout(postinsql.bind(null, topicId), 4000);

有关更多信息,请参见以下 MDN 链接:
https://developer.mozilla.org/en/docs/DOM/window.setTimeout#highlighter_547041 https://developer.mozilla.org/en/docs/JavaScript/Reference/Global_Objects/Function/bind#With_setTimeout

一些答案是正确的,但令人费解。

4 年后,我再次回答这个问题,因为我仍然遇到过分复杂的代码来解决这个问题。有一个优雅的解决方案。

首先,在调用 setTimeout 时不要将字符串作为第一个参数传递,因为它有效地调用了对慢速 “eval” 函数的调用。

那么我们如何将参数传递给超时函数呢?通过使用闭包:

settopic=function(topicid){
  setTimeout(function(){
    //thanks to closure, topicid is visible here
    postinsql(topicid);
  },4000);
}

...
if (xhr.readyState==4){
  settopic(xhr.responseText);
}

有些人建议在调用超时函数时使用匿名函数:

if (xhr.readyState==4){
  setTimeout(function(){
    settopic(xhr.responseText);
  },4000);
}

语法可行。但是,在调用 settopic 的时间(即 4 秒钟后)时,XHR 对象可能不相同。因此, 预先绑定变量很重要。

我的答案:

setTimeout((function(topicId) {
  return function() {
    postinsql(topicId);
  };
})(topicId), 4000);

说明:

创建的匿名函数将返回另一个匿名函数。该函数可以访问最初传递的topicId ,因此不会出错。立即调用第一个匿名函数,并传入topicId ,因此延迟注册的函数可以在调用时通过闭包访问topicId

要么

这基本上转换为:

setTimeout(function() {
  postinsql(topicId); // topicId inside higher scope (passed to returning function)
}, 4000);

编辑:我看到了相同的答案,所以看看他。但是我没有偷他的答案!我忘了看。阅读说明,看看是否有助于理解代码。

更换

setTimeout("postinsql(topicId)", 4000);

setTimeout("postinsql(" + topicId + ")", 4000);

或更妙的是,用匿名函数替换字符串表达式

setTimeout(function () { postinsql(topicId); }, 4000);

编辑:

Brownstone 的注释不正确,这将按预期运行,如在 Firebug 控制台中运行该注释所示

(function() {
  function postinsql(id) {
    console.log(id);
  }
  var topicId = 3
  window.setTimeout("postinsql(" + topicId + ")",4000); // outputs 3 after 4 seconds
})();

请注意,我与其他人保持一致,您应该避免将字符串传递给setTimeout因为这将在字符串上调用eval()而不是传递一个函数。

支持 setTimeout 中参数的最简单的跨浏览器解决方案:

setTimeout(function() {
    postinsql(topicId);
}, 4000)

如果您不介意不支持 IE 9 及更低版本:

setTimeout(postinsql, 4000, topicId);

setTimeout桌面浏览器兼容性

setTimeout移动浏览器兼容性

https://developer.mozilla.org/zh-CN/docs/Web/API/WindowTimers/setTimeout