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

我有一些如下的JavaScript代码:

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

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

我收到topicId未定义的错误,在使用该setTimeout()功能之前,一切都在工作

我希望postinsql(topicId)一段时间后调用我的函数。我该怎么办?

逆天宝儿米亚2020/03/10 14:16:15

setTimeout是WHAT WG定义的DOM的一部分。

https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html

您想要的方法是:

handle = self.setTimeout( handler [, timeout [, arguments... ] ] )

安排超时时间,以在超时毫秒后运行处理程序。任何参数都直接传递给处理程序。

setTimeout(postinsql, 4000, topicId);

显然,IE10支持额外的参数。另外,您可以使用setTimeout(postinsql.bind(null, topicId), 4000);,但是传递额外的参数会更简单,这是可取的。

历史事实:在VBScript时代,在JScript中,setTimeout的第三个参数是语言,为字符串,默认为“ JScript”,但可以选择使用“ VBScript”。https://docs.microsoft.com/zh-cn/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa741500(v%3Dvs.85)

乐米亚2020/03/10 14:16:15

我想你要:

setTimeout("postinsql(" + topicId + ")", 4000);
2020/03/10 14:16:15

回答问题,但使用带有2个参数的简单加法函数。

var x = 3, y = 4;

setTimeout(function(arg1, arg2) { 
      delayedSum(arg1, arg2);
}(x, y), 1000);

function delayedSum(param1, param2) {
     alert(param1 + param2); // 7
}
乐米亚2020/03/10 14:16:15

这适用于所有浏览器(IE是一个奇怪的球)

setTimeout( (function(x) {
return function() {
        postinsql(x);
    };
})(topicId) , 4000);
小宇宙Pro2020/03/10 14:16:15

请注意,根据错误消息“ topicId”未定义的原因是,它在执行setTimeout时作为局部变量存在,但在延迟调用postinsql时不存在。变量生存期尤其要注意,尤其是在尝试将“ this”作为对象引用传递时。

听说您可以将topicId作为第三个参数传递给setTimeout函数。没有给出太多细节,但是我获得了足够的信息来使它起作用,并且在Safari中很成功。我不知道它们对“毫秒错误”的含义。在这里查看:

http://www.howtocreate.co.uk/tutorials/javascript/timers

逆天乐2020/03/10 14:16:15

通常,如果您需要将函数作为带有特定参数的回调传递,则可以使用高阶函数。ES6非常优雅:

const someFunction = (params) => () => {
  //do whatever
};

setTimeout(someFunction(params), 1000);

或如果someFunction是第一订单:

setTimeout(() => someFunction(params), 1000); 
谷若汐2020/03/10 14:16:15

更换

 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()字符串,而是传递一个函数。

神乐Jim2020/03/10 14:16:15

您可以通过以下方式将参数传递给setTimeout回调函数:

setTimeout(函数,毫秒,param1,param2,...)

例如。

function myFunction() {
  setTimeout(alertMsg, 3000, "Hello");
}

function alertMsg(message) {
    alert(message)
}
老丝镜风2020/03/10 14:16:15

我的答案:

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

说明:

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

要么

这基本上转换为:

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

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

泡芙飞云2020/03/10 14:16:15

支持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

ㄏ囧囧ㄟ2020/03/10 14:16:15

我知道它已经很老了,但我想在此添加我的(首选)口味。

我认为实现此目的的一种很易读的方法是将传递topicId给一个函数,该函数进而使用参数在内部引用主题ID。即使稍后将topicId在外部更改此值也不会更改

var topicId = xmlhttp.responseText;
var fDelayed = function(tid) {
  return function() {
    postinsql(tid);
  };
}
setTimeout(fDelayed(topicId),4000);

或简称:

var topicId = xmlhttp.responseText;
setTimeout(function(tid) {
  return function() { postinsql(tid); };
}(topicId), 4000);
神奇阿良Jim2020/03/10 14:16:15

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

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对象可能不相同。因此,预先绑定变量很重要

Davaid小卤蛋2020/03/10 14:16:15

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

使用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

前端L2020/03/10 14:16:15

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

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

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

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

梅乐2020/03/10 14:16:15

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

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

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

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

小宇宙2020/03/10 14:16:15

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

例:

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

更多细节:

Mandy古一2020/03/10 14:16:15
setTimeout(function() {
    postinsql(topicId);
}, 4000)

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

更新:

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

例:

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