提问人:Zeeshan Rang 提问时间:7/28/2009 最后编辑:Donald DuckZeeshan Rang 更新时间:6/16/2023 访问量:764727
如何将参数传递给 setTimeout() 回调?
How can I pass a parameter to a setTimeout() callback?
问:
我有一些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)
答:
setTimeout(function() {
postinsql(topicId);
}, 4000)
您需要将匿名函数作为参数而不是字符串提供,后一种方法甚至不应该按照 ECMAScript 规范工作,但浏览器只是宽松。这是正确的解决方案,在使用 or 时永远不要依赖将字符串作为“函数”传递,它的速度较慢,因为它必须被评估并且它是不对的。setTimeout()
setInterval()
更新:
正如 Hobblin 在对问题的评论中所说,现在您可以使用 Function.prototype.bind()
将参数传递给 setTimeout 中的函数。
例:
setTimeout(postinsql.bind(null, topicId), 4000);
评论
window.setTimeout
是一个 DOM 方法,因此不是由 ECMAScript 规范定义的。传递字符串在浏览器中一直有效,并且是一个事实上的标准——事实上,传递函数对象的能力是后来在 JavaScript 1.2 中添加的——它是 HTML5 草案规范的明确组成部分 (whatwg.org/specs/web-apps/current-work/multipage/...)。但是,使用字符串而不是函数对象通常被认为是糟糕的样式,因为它本质上是延迟的一种形式。eval()
取代
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("postinsql(" + topicId + ")", 4000);
评论
JSON.stringify
JSON.parse
请注意,根据错误消息,topicId “未定义”的原因是,在执行 setTimeout 时,它作为局部变量存在,但在发生对 postinsql 的延迟调用时,则不然。变量生存期尤为重要,尤其是在尝试将“this”作为对象引用传递时。
我听说您可以将 topicId 作为第三个参数传递给 setTimeout 函数。没有给出太多细节,但我得到了足够的信息来让它工作,而且它在 Safari 中很成功。我不知道他们对“毫秒误差”是什么意思。在这里查看:
http://www.howtocreate.co.uk/tutorials/javascript/timers
在现代浏览器(即 IE11 及更高版本)中,“setTimeout”接收第三个参数,该参数作为参数发送到计时器末尾的内部函数。
例:
var hello = "Hello World";
setTimeout(alert, 1000, hello);
更多详情:
- https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers.setTimeout
- http://arguments.callee.info/2008/11/10/passing-arguments-to-settimeout-and-setinterval/
评论
经过一些研究和测试,唯一正确的实现是:
setTimeout(yourFunctionReference, 4000, param1, param2, paramN);
setTimeout 会将所有额外的参数传递给您的函数,以便可以在那里处理它们。
匿名函数可以用于非常基本的东西,但是在必须使用“this”的对象实例中,没有办法使其工作。 任何匿名函数都会将“this”更改为指向窗口,因此您将丢失对象引用。
评论
var that = this; setTimeout( function() { that.foo(); }, 1000);
这是一个非常古老的问题,答案已经“正确”了,但我想我会提到另一种没有人在这里提到的方法。这是从优秀的下划线库复制和粘贴的:
_.delay = function(func, wait) {
var args = slice.call(arguments, 2);
return setTimeout(function(){ return func.apply(null, args); }, wait);
};
您可以将任意数量的参数传递给 setTimeout 调用的函数,并且作为额外的奖励(嗯,通常是奖励),当您调用 setTimeout 时,传递给函数的参数的值会被冻结,因此,如果它们在调用 setTimeout() 和超时之间的某个时间点更改值, 井。。。这不再那么可怕了:)
这里有一把小提琴,你可以明白我的意思。
评论
@Jiri Vetyska感谢您的帖子,但是您的示例中存在问题。 我需要将悬停的目标(这个)传递给超时函数,我尝试了您的方法。在 IE9 中测试 - 不起作用。 我还做了一些研究,似乎正如这里所指出的,第三个参数是正在使用的脚本语言。没有提及其他参数。
因此,我按照@meder的回答,用这段代码解决了我的问题:
$('.targetItemClass').hover(ItemHoverIn, ItemHoverOut);
function ItemHoverIn() {
//some code here
}
function ItemHoverOut() {
var THIS = this;
setTimeout(
function () { ItemHoverOut_timeout(THIS); },
100
);
}
function ItemHoverOut_timeout(target) {
//do something with target which is hovered out
}
希望,这对别人有用。
霍布林已经对这个问题发表了评论,但这应该是一个答案!
使用是最干净、最灵活的方法(具有能够设置上下文的额外好处):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
评论
setTimeout(postinsql.bind(this, topicId), 4000);
bind
我如何解决这个阶段?
就像那样:
setTimeout((function(_deepFunction ,_deepData){
var _deepResultFunction = function _deepResultFunction(){
_deepFunction(_deepData);
};
return _deepResultFunction;
})(fromOuterFunction, fromOuterData ) , 1000 );
setTimeout 等待对函数的引用,所以我在闭包中创建了它,它解释我的数据并返回一个带有我数据的良好实例的函数!
也许你可以改进这部分:
_deepFunction(_deepData);
// change to something like :
_deepFunction.apply(contextFromParams , args);
我在 chrome、firefox 和 IE 上测试了它,它执行得很好,我不知道性能,但我需要它才能工作。
样品测试:
myDelay_function = function(fn , params , ctxt , _time){
setTimeout((function(_deepFunction ,_deepData, _deepCtxt){
var _deepResultFunction = function _deepResultFunction(){
//_deepFunction(_deepData);
_deepFunction.call( _deepCtxt , _deepData);
};
return _deepResultFunction;
})(fn , params , ctxt)
, _time)
};
// the function to be used :
myFunc = function(param){ console.log(param + this.name) }
// note that we call this.name
// a context object :
myObjet = {
id : "myId" ,
name : "myName"
}
// setting a parmeter
myParamter = "I am the outer parameter : ";
//and now let's make the call :
myDelay_function(myFunc , myParamter , myObjet , 1000)
// this will produce this result on the console line :
// I am the outer parameter : myName
也许您可以更改签名以使其更符合要求:
myNass_setTimeOut = function (fn , _time , params , ctxt ){
return setTimeout((function(_deepFunction ,_deepData, _deepCtxt){
var _deepResultFunction = function _deepResultFunction(){
//_deepFunction(_deepData);
_deepFunction.apply( _deepCtxt , _deepData);
};
return _deepResultFunction;
})(fn , params , ctxt)
, _time)
};
// and try again :
for(var i=0; i<10; i++){
myNass_setTimeOut(console.log ,1000 , [i] , console)
}
最后回答原来的问题:
myNass_setTimeOut( postinsql, 4000, topicId );
希望能帮到你!
PS:对不起,英语不是我的母语!
评论
我最近遇到了需要在循环中使用的独特情况。了解这一点可以帮助您了解如何将参数传递给 。setTimeout
setTimeout
方法 1
根据 Sukima 的建议,使用 和 :forEach
Object.keys
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
或者,如果您不能使用 或 ,请使用 IIFE:forEach
bind
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 中使用 with。Object.keys
forEach
评论
.bind
bind
Object.keys
forEach
async
forEach
map
reduce
我知道它很旧,但我想添加我的(首选)味道。
我认为实现这一点的一种非常可读的方法是将 传递给一个函数,该函数又使用参数在内部引用主题 ID。此值不会更改,即使在外部不久后也会更改。topicId
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);
由于 IE 中的第三个 optonal 参数存在问题,并且使用闭包会阻止我们更改变量(例如在循环中)并仍然获得所需的结果,因此我建议以下解决方案。
我们可以尝试使用递归,如下所示:
var i = 0;
var hellos = ["Hello World1!", "Hello World2!", "Hello World3!", "Hello World4!", "Hello World5!"];
if(hellos.length > 0) timeout();
function timeout() {
document.write('<p>' + hellos[i] + '<p>');
i++;
if (i < hellos.length)
setTimeout(timeout, 500);
}
我们需要确保没有其他变量会改变这些变量,并且我们编写一个适当的递归条件来避免无限递归。
有些答案是正确的,但令人费解。
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 对象可能就不一样了。因此,预先绑定变量非常重要。
评论
David Meister 的答案似乎处理了在调用 setTimeout() 之后但在调用匿名函数之前可能立即更改的参数。但是太麻烦了,不是很明显。我发现了一种使用 IIFE(立即初始化函数表达式)做几乎相同事情的优雅方法。
在下面的示例中,变量被传递给 IIFE,IIFE 将其保存在其闭包中,直到调用延迟函数。即使变量在显示的代码后立即更改,也会做正确的事情。currentList
currentList
setInterval()
如果没有这种 IIFE 技术,该函数肯定会被 DOM 中的每个元素调用,但所有这些调用将只看到最后一个元素的文本值。setTimeout()
h2
h2
<script>
// Wait for the document to load.
$(document).ready(function() {
$("h2").each(function (index) {
currentList = $(this).text();
(function (param1, param2) {
setTimeout(function() {
$("span").text(param1 + ' : ' + param2 );
}, param1 * 1000);
})(index, currentList);
});
</script>
这适用于所有浏览器(IE是一个奇怪的)
setTimeout( (function(x) {
return function() {
postinsql(x);
};
})(topicId) , 4000);
在 setTimeout 中支持参数的最简单的跨浏览器解决方案:
setTimeout(function() {
postinsql(topicId);
}, 4000)
如果您不介意不支持 IE 9 及更低版本:
setTimeout(postinsql, 4000, topicId);
https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout
我的回答:
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);
编辑:我看到了同样的答案,所以看看他的。但我没有偷他的答案!我只是忘了看。阅读说明,看看它是否有助于理解代码。
评论
topicId
通常,如果需要将函数作为具有特定参数的回调传递,则可以使用高阶函数。这在 ES6 中非常优雅:
const someFunction = (params) => () => {
//do whatever
};
setTimeout(someFunction(params), 1000);
或者,如果是一阶:someFunction
setTimeout(() => someFunction(params), 1000);
评论
您可以尝试像这样“apply()”的默认功能,您可以在数组中根据需要传递更多数量的参数
function postinsql(topicId)
{
//alert(topicId);
}
setTimeout(
postinsql.apply(window,["mytopic"])
,500);
如果你想将变量作为参数传递,让我们试试这个
如果要求是函数,var 是 parmas,那么试试这个
setTimeout((param1,param2) => {
alert(param1 + param2);
postinsql(topicId);
},2000,'msg1', 'msg2')
如果 requirement 只是作为参数的变量,那么试试这个
setTimeout((param1,param2) => { alert(param1 + param2) },2000,'msg1', 'msg2')
您可以在 ES5 和 ES6 上尝试此操作
这是三个非常简单明了的答案:
function fun() {
console.log(this.prop1, this.prop2, this.prop3);
}
let obj = { prop1: 'one', prop2: 'two', prop3: 'three' };
let bound = fun.bind(obj);
setTimeout(bound, 3000);
// or
function funOut(par1, par2, par3) {
return function() {
console.log(par1, par2, par3);
}
};
setTimeout(funOut('one', 'two', 'three'), 5000);
// or
let funny = function(a, b, c) { console.log(a, b, c); };
setTimeout(funny, 2000, 'hello', 'worldly', 'people');
这是三个非常简单明了的答案:
function fun() {
console.log(this.prop1, this.prop2, this.prop3);
}
let obj = { prop1: 'one', prop2: 'two', prop3: 'three' };
let bound = fun.bind(obj);
setTimeout(bound, 3000);
// or
function funOut(par1, par2, par3) {
return function() {
console.log(par1, par2, par3);
}
};
setTimeout(funOut('one', 'two', 'three'), 5000);
// or
let funny = function(a, b, c) { console.log(a, b, c); };
setTimeout(funny, 2000, 'hello', 'worldly', 'people');
您可以将参数传递给 setTimeout 回调函数,如下所示:
setTimeout(函数, 毫秒, param1, param2, ...)
例如。
function myFunction() {
setTimeout(alertMsg, 3000, "Hello");
}
function alertMsg(message) {
alert(message)
}
评论
setTimeout( (p) => { console.log(p); }, 1000, "hi" );
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://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa741500(v%3Dvs.85)
我知道自从提出这个问题以来已经有 10 年了,但是,如果您一直滚动到这里,我认为您仍然面临一些问题。梅德尔·奥穆拉利耶夫(Meder Omuraliev)的解决方案是最简单的解决方案,可能会对我们大多数人有所帮助,但对于那些不想有任何约束的人来说,这里是:
- 将 Param 用于 setTimeout
setTimeout(function(p){
//p == param1
},3000,param1);
- 使用立即调用的函数表达式 (IIFE)
let param1 = 'demon';
setTimeout(function(p){
// p == 'demon'
},2000,(function(){
return param1;
})()
);
- 问题的解决方案
function statechangedPostQuestion()
{
//alert("statechangedPostQuestion");
if (xmlhttp.readyState==4)
{
setTimeout(postinsql,4000,(function(){
return xmlhttp.responseText;
})());
}
}
function postinsql(topicId)
{
//alert(topicId);
}
回答问题,但通过带有 2 个参数的简单加法函数。
var x = 3, y = 4;
setTimeout(function(arg1, arg2) {
return () => delayedSum(arg1, arg2);
}(x, y), 1000);
function delayedSum(param1, param2) {
alert(param1 + param2); // 7
}
评论
您必须从函数调用中删除引号,如下所示:setTimeOut
setTimeout(postinsql(topicId),4000);
评论
postinsql()
//Some function, with some arguments, that need to run with arguments
var a = function a(b, c, d, e){console.log(b, c, d, e);}
//Another function, where setTimeout using for function "a", this have the same arguments
var f = function f(b, c, d, e){ setTimeout(a.apply(this, arguments), 100);}
f(1,2,3,4); //run
//Another function, where setTimeout using for function "a", but some another arguments using, in different order
var g = function g(b, c, d, e){ setTimeout(function(d, c, b){a.apply(this, arguments);}, 100, d, c, b);}
g(1,2,3,4);
评论
只需在 setTimeout function() 中添加 Parameter 后,就会得到作为参数的 setTimeout function(),milliseconds
name = "Mickey Mouse";
setTimeout(function(myVar){
console.log("hello " + myVar);
},1000,name);
评论