当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《如何将参数传递给setTimeout()回调?》经验,为你挑选了10个好方法。

我有一些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)在一段时间后调用我的函数.我该怎么办?



1> meder omural..:
setTimeout(function() {
    postinsql(topicId);
}, 4000)

您需要将匿名函数作为参数而不是字符串提供,后一种方法甚至不应该按照ECMAScript规范工作,但浏览器只是宽松的.这是正确的解决方案,不要依赖于在使用时将字符串作为"函数"传递,setTimeout()或者setInterval()它更慢,因为它必须被评估并且它不正确.

更新:

正如Hobblin在对该问题的评论中所说,现在你可以将参数传递给setTimeout中的函数 Function.prototype.bind()

例:

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


`window.setTimeout`是一个DOM方法,因此ECMAScript规范没有定义它.传递一个字符串一直在浏览器中工作,并且是_de facto_标准 - 事实上,稍后使用JavaScript 1.2添加了传递函数对象的能力 - 它明确是HTML5草案规范的一部分(http://www.whatwg .ORG /规格/网络应用/电流工作/多页/ browsers.html浏览#GET-的定时任务).但是,使用字符串而不是函数对象通常被认为是不好的样式,因为它本质上是一种延迟的`eval()`.
@pilau这正是我的问题:如果匿名函数中使用的变量在超时之前发生了变化(例如在for循环中),那么它也会在函数内部发生变化.因此,在我的示例设置中,for循环中的5个不同的超时实际上最终使用相同的变量.使用此答案时要小心!
如果在设置超时后但在调用函数之前更改了topicId会发生什么?
@pilau使用另一个闭包将帮助topicId = 12; function postinsql(topicId){console.log(topicId); function setTimeOutWithClosure(topicId){setTimeout(function(){postinsql(topicId);},1000)} setTimeOutFunction(topicId); topicId = 13;
var temp = setTimeout(function(){postinsql(topicId);},4000); clearTimeout(温度); ??

2> Fabio Phms..:

在现代浏览器中,"setTimeout"接收第三个参数,该参数作为参数发送到计时器末尾的内部函数.

例:

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


3> Jiri Vetyska..:

在做了一些研究和测试之后,唯一正确的实现是:

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

setTimeout会将所有额外参数传递给您的函数,以便在那里处理它们.

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


我心里感到悲伤,我必须告知:这在互联网浏览器中不起作用.:/所有额外的参数都是未定义的.
我只是使用`var that = this; setTimeout(function(){that.foo();},1000);`
这与[Fabio](http://stackoverflow.com/a/7503942/1269037)完全相同.
这是正确的,并且是在HTML5中指定的。http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-setinterval

4> David Meiste..:

这是一个非常古老的问题,已有"正确"的答案,但我想我会提到另一种方法,没有人在这里提到过.这是从优秀的下划线库中复制和粘贴的:

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

您可以将所需的参数传递给setTimeout调用的函数,作为额外的奖励(通常是奖金),当您调用setTimeout时,传递给函数的参数值将被冻结,因此如果它们更改了值在调用setTimeout()和超时之间的某个时刻,好吧......那不再那么令人沮丧了:)

这是一个小提琴,你可以看到我的意思.


这个答案确实有效,但你似乎有一些我没有的库.以下是它的小工具:而不是slice.call,使用Array.prototype.slice.call(arguments,2)
@Melanie"一些图书馆"?我在答案中说它是下划线库 - http://underscorejs.org/.但是,是的,Array.prototype.slice是别名来切片到那个库里面,所以你必须自己做,如果你不使用它,好点:)

5> David Sherre..:

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

方法1

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

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

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

我推荐这种方法.

方法2

使用 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);
}

虽然我还是会建议使用Object.keysforEach在ES6.


注意:`.bind`不会为IE8工作和低于[参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Browser_compatibility.我最终使用了Schien的解决方案:http://stackoverflow.com/a/21213723/1876899

6> dain..:

霍布林已就这个问题对此进行了评论,但这应该是一个答案!

使用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 /绑定#With_setTimeout



7> Schien..:

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

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



8> 小智..:

我的答案:

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);

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



9> Russ Cam..:

更换

 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()字符串而不是传递函数.


@brownstone:那是不对的.超时触发时将评估该字符串.

10> Michael J. C..:

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

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

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

setTimeout(postinsql, 4000, topicId);

setTimeout桌面浏览器兼容性

setTimeout移动浏览器兼容性

https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout

推荐阅读
依然-狠幸福
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有