我有一些看起来像的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)
函数。
我该怎么办?
答案 0 :(得分:1042)
setTimeout(function() {
postinsql(topicId);
}, 4000)
您需要将匿名函数作为参数而不是字符串提供,后一种方法甚至不应该按照ECMAScript规范工作,但浏览器只是宽松的。这是正确的解决方案,在使用setTimeout()
或setInterval()
时,不要依赖于将字符串作为“函数”传递,它的速度较慢,因为它必须进行评估而且不正确。
<强>更新强>
正如Hobblin在对该问题的评论中所说,现在你可以使用Function.prototype.bind()
示例:
setTimeout(postinsql.bind(null, topicId), 4000);
答案 1 :(得分:652)
在现代浏览器中,“setTimeout”接收第三个参数,该参数作为参数发送到计时器末尾的内部函数。
示例:
var hello = "Hello World";
setTimeout(alert, 1000, hello);
更多详情:
答案 2 :(得分:132)
经过一些研究和测试后,唯一正确的实施是:
setTimeout(yourFunctionReference, 4000, param1, param2, paramN);
setTimeout会将所有额外参数传递给您的函数,以便在那里进行处理。
匿名函数可以用于非常基本的东西,但是在你必须使用“this”的对象的实例中,没有办法让它工作。 任何匿名函数都会将“this”更改为指向窗口,因此您将丢失对象引用。
答案 3 :(得分:44)
这是一个非常古老的问题,已经有了“正确”的答案,但我想我会提到另一种方法,这里没有人提到过。这是从优秀的underscore库中复制和粘贴的:
_.delay = function(func, wait) {
var args = slice.call(arguments, 2);
return setTimeout(function(){ return func.apply(null, args); }, wait);
};
你可以将你想要的参数传递给setTimeout 和调用的函数作为额外的奖励(好吧,通常是奖金)传递给你的函数的参数的值被冻结当你调用setTimeout时,所以如果他们在调用setTimeout()和超时之间的某个时刻改变了值,那么......那不再那么令人沮丧了:)
Here's a fiddle你可以看到我的意思。
答案 4 :(得分:37)
我最近遇到了需要在循环中使用setTimeout
的独特情况。了解这一点可以帮助您了解如何将参数传递给setTimeout
。
方法1
根据Sukima的suggestion使用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
如果您无法使用forEach
或bind
,请使用IIFE:
var i = 0;
for (var propertyName in testObject) {
setTimeout((function(propertyName) {
return function() {
console.log(testObject[propertyName]);
};
})(propertyName), i++ * 1000);
}
方法4
但如果你不关心IE&lt; 10,那么你可以使用Fabio的suggestion:
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.keys
和forEach
。
答案 5 :(得分:22)
霍布林已经就这个问题发表了评论,但这应该是一个答案!
使用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
答案 6 :(得分:16)
有些答案是正确但令人费解的。
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对象可能不同。因此,pre-bind the variables非常重要。
答案 7 :(得分:10)
我的回答:
setTimeout((function(topicId) {
return function() {
postinsql(topicId);
};
})(topicId), 4000);
说明:
创建的匿名函数返回另一个匿名函数。此函数可以访问最初传递的
topicId
,因此不会出错。第一个匿名函数立即被调用,传入topicId
,因此具有延迟的注册函数在调用时可以通过闭包访问topicId
。
OR
这基本上转换为:
setTimeout(function() {
postinsql(topicId); // topicId inside higher scope (passed to returning function)
}, 4000);
编辑:我看到了同样的答案,所以看看他的。但我没有窃取他的答案!我只是忘了看。阅读说明,看看它是否有助于理解代码。
答案 8 :(得分:9)
替换
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()
而是传递一个函数。
答案 9 :(得分:6)
支持setTimeout参数的最简单的跨浏览器解决方案:
setTimeout(function() {
postinsql(topicId);
}, 4000)
如果您不介意不支持IE 9及更低版本:
setTimeout(postinsql, 4000, topicId);
https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout
答案 10 :(得分:3)
David Meister的回答似乎处理了在调用setTimeout()之后但在调用匿名函数之前可能立即更改的参数。但它太麻烦而且不太明显。我发现了一种使用IIFE(立即调用函数表达式)做同样事情的优雅方法。
在下面的示例中,currentList
变量传递给IIFE,后者将其保存在闭包中,直到调用延迟函数。即使变量currentList
在显示的代码之后立即更改,setInterval()
也会做正确的事。
如果没有这种IIFE技术,肯定会为DOM中的每个setTimeout()
元素调用h2
函数,但所有这些调用只会看到 last 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>
答案 11 :(得分:3)
这适用于所有浏览器(IE是一个古怪的)
setTimeout( (function(x) {
return function() {
postinsql(x);
};
})(topicId) , 4000);
答案 12 :(得分:3)
我知道它已经过时但我想添加我的(首选)风味。
我认为实现这一目标的一种非常易读的方法是将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);
答案 13 :(得分:2)
如果要将变量作为参数传递,请尝试
如果要求是函数,而var为parma,则尝试此操作
setTimeout((param1,param2) => {
alert(param1 + param2);
postinsql(topicId);
},2000,'msg1', 'msg2')
如果要求仅是将变量作为参数,则尝试此操作
setTimeout((param1,param2) => { alert(param1 + param2) },2000,'msg1', 'msg2')
您可以在ES5和ES6上尝试使用
答案 14 :(得分:2)
通常,如果需要将函数作为具有特定参数的回调传递,则可以使用更高阶函数。这与ES6非常优雅:
const someFunction = (params) => () => {
//do whatever
};
setTimeout(someFunction(params), 1000);
或者如果someFunction
是第一顺序:
setTimeout(() => someFunction(params), 1000);
答案 15 :(得分:2)
请注意,对于错误消息,topicId“未定义”的原因是它在执行setTimeout时作为局部变量存在,但在发生对postinsql的延迟调用时则不存在。可变寿命对于注意尤为重要,特别是在尝试将“this”作为对象引用时。
我听说你可以将topicId作为第三个参数传递给setTimeout函数。没有给出太多细节但是我得到了足够的信息来使它工作,并且它在Safari中很成功。我不知道他们对“毫秒错误”的意思。在这里查看:
答案 16 :(得分:2)
我如何解决这个阶段?
就像那样:
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:抱歉,但英语不是我的母语!
答案 17 :(得分:1)
您可以尝试使用'apply()'这样的默认功能,您可以在数组中传递更多数量的参数
function postinsql(topicId)
{
//alert(topicId);
}
setTimeout(
postinsql.apply(window,["mytopic"])
,500);
答案 18 :(得分:1)
我知道问这个问题已有10年了,但是,如果您滚动到此处,我仍然认为您仍然面临一些问题。 Meder Omuraliev的解决方案是最简单的解决方案,可能会对我们大多数人有所帮助,但是对于那些不想拥有任何约束力的人,这里是:
setTimeout(function(p){
//p == param1
},3000,param1);
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);
}
答案 19 :(得分:1)
您必须像这样从setTimeOut
函数调用中删除报价:
setTimeout(postinsql(topicId),4000);
答案 20 :(得分:0)
@Jiri Vetyska感谢你的帖子,但是你的例子有些不对劲。 我需要将目标悬停(这个)传递给超时功能,我尝试了你的方法。在IE9中测试 - 不起作用。 我也进行了一些研究,看起来如同here所指出的,第三个参数是正在使用的脚本语言。没有提及其他参数。
所以,我跟着@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
}
希望,这对其他人有用。
答案 21 :(得分:0)
由于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);
}
我们需要确保没有其他任何内容更改这些变量,并且我们编写了正确的递归条件以避免无限递归。
答案 22 :(得分:0)
//这是三个非常简单明了的答案:
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');
答案 23 :(得分:0)
您可以通过以下方式将参数传递给setTimeout回调函数:
setTimeout(函数,毫秒,param1,param2等)
例如
function myFunction() {
setTimeout(alertMsg, 3000, "Hello");
}
function alertMsg(message) {
alert(message)
}
答案 24 :(得分:0)
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/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa741500(v%3Dvs.85)
答案 25 :(得分:0)
//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);
答案 26 :(得分:-1)
我想你想要:
setTimeout("postinsql(" + topicId + ")", 4000);
答案 27 :(得分:-1)
//这是三个非常简单明了的答案:
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');
答案 28 :(得分:-2)
通过一个带有2个参数的简单加法函数来回答问题。
var x = 3, y = 4;
setTimeout(function(arg1, arg2) {
delayedSum(arg1, arg2);
}(x, y), 1000);
function delayedSum(param1, param2) {
alert(param1 + param2); // 7
}