Javascript 使用setTimeout()调用函数
简单地说 为什么Javascript 使用setTimeout()调用函数,javascript,settimeout,Javascript,Settimeout,简单地说 为什么 setTimeout('playNote('+currentaudio.id+', '+noteTime+')', delay); 工作正常,在指定的延迟后调用函数,但是 setTimeout(playNote(currentaudio.id,noteTime), delay); 是否同时调用函数playNote (这些setTimeout()位于for循环中) 或者,如果我的解释太难理解,那么这两个函数之间的区别是什么?试试这个 setTimeout(function()
setTimeout('playNote('+currentaudio.id+', '+noteTime+')', delay);
工作正常,在指定的延迟后调用函数,但是
setTimeout(playNote(currentaudio.id,noteTime), delay);
是否同时调用函数playNote
(这些setTimeout()位于for循环中)
或者,如果我的解释太难理解,那么这两个函数之间的区别是什么?试试这个
setTimeout(function() { playNote(currentaudio.id,noteTime) }, delay);
因为您告诉它的第二个表单首先调用playNote函数,然后将返回值从它传递给setTimeout。您列出的第一个表单有效,因为它将在
delay
末尾计算字符串。使用eval()
通常不是一个好主意,因此应该避免这种情况
第二种方法不起作用,因为您立即使用执行函数对象。如果使用playNote(…)
格式,则会立即执行playNote
,因此延迟结束时不会发生任何事情
相反,您必须向setTimeout传递一个匿名函数,因此正确的形式是:
setTimeout(function() { playNote(currentaudio.id,noteTime) }, delay);
请注意,您正在传递整个函数表达式,因此它将保留匿名函数,并且仅在延迟结束时执行它
您还可以传递setTimeout
引用,因为引用不会立即执行,但是您不能传递参数:
setTimeout(playNote, delay);
setTimeout(playNote, delay);
注意: 对于重复事件,您可以使用,您可以将
setInterval()
设置为变量,并使用该变量停止间隔
您说您在for
循环中使用setTimeout()
。在许多情况下,最好在递归函数中使用setTimeout()
。这是因为在for
循环中,setTimeout()
中使用的变量将不是setTimeout()
开始时的变量,而是在函数启动延迟后的变量
只需使用递归函数就可以避开整个问题
使用递归处理可变延迟时间:
不要使用字符串超时。它是有效的
评估
,这是一件坏事。它之所以有效,是因为它正在将currentaudio.id
和noteTime
转换为它们自身的字符串表示形式,并将其隐藏在代码中。这只适用于那些值具有生成JavaScript文本语法的toString()
s以重新创建该值的情况,这对于Number
是正确的,但对于其他很多情况则不适用
setTimeout(playNote(currentaudio.id, noteTime), delay);
这是一个函数调用playNote
立即被调用,函数返回的结果(可能是undefined
)被传递到setTimeout()
,而不是您想要的
正如其他答案所提到的,您可以使用带闭包的内联函数表达式来引用currentaudio
和noteTime
:
setTimeout(function() {
playNote(currentaudio.id, noteTime);
}, delay);
但是,如果您在一个循环中,currentaudio
或noteTime
在循环中每次都是不同的,那么您就遇到了闭合循环问题:在每个超时中都会引用相同的变量,因此每次调用它们时,您都会得到相同的值,循环提前完成时留在变量中的值
您可以使用另一个闭包来解决此问题,为循环的每次迭代获取变量值的副本:
setTimeout(function() {
return function(currentaudio, noteTime) {
playNote(currentaudio.id, noteTime);
};
}(currentaudio, noteTime), delay);
但现在这有点难看了。更好的是函数#bind
,它将为您部分应用函数:
setTimeout(playNote.bind(window, currentaudio.id, noteTime), delay);
(窗口
用于在函数内部设置此
的值,这是bind()
的一项功能,此处不需要。)
不过,这是ECMAScript第五版的一项功能,并非所有浏览器都支持。因此,如果您想使用它,您必须首先在支持中进行黑客攻击,例如:
// Make ECMA262-5 Function#bind work on older browsers
//
if (!('bind' in Function.prototype)) {
Function.prototype.bind= function(owner) {
var that= this;
if (arguments.length<=1) {
return function() {
return that.apply(owner, arguments);
};
} else {
var args= Array.prototype.slice.call(arguments, 1);
return function() {
return that.apply(owner, arguments.length===0? args : args.concat(Array.prototype.slice.call(arguments)));
};
}
};
}
//使ECMA262-5功能#绑定在旧浏览器上工作
//
if(!('bind'在Function.prototype中)){
Function.prototype.bind=函数(所有者){
var=这个;
如果(arguments.length我真的在这个网站上创建了一个帐户来评论Peter Ajtai的答案(目前投票率最高),结果发现你需要50个代表(不管是什么)来评论,所以我会把它作为一个答案,因为它可能值得指出几件事
他在答复中说:
您还可以传递setTimeout
引用,因为引用不会立即执行,但是您不能传递参数:
setTimeout(playNote, delay);
setTimeout(playNote, delay);
这不是真的。在给出函数引用和延迟量后,任何附加参数都会被解析为引用函数的参数。下面的方法比在函数中包装函数调用更好
setTimeout(playNote, delay, currentaudio.id, noteTime)
始终查阅文档
正如彼得指出的,如果你想改变每个<代码>播放笔记()/代码>之间的延迟,或者如果你想在每一个代码< > PrPoEnter()/<代码>之间有相同的延迟,那么递归函数将是个好主意。
还值得注意的是,如果要将for循环的i
解析为setTimeout()
,则需要将其封装在函数中,详细说明如下这可能有助于理解javascript何时执行代码,以及何时等待执行某些操作:
let foo2=function foo(bar=baz()){console.log(bar);return bar()}
- javascript执行的第一件事是函数构造函数,并创建一个函数对象。您可以使用function关键字语法或
=>
语法,并得到类似的()结果
- 然后将刚刚创建的函数分配给变量
foo2
- 此时,没有运行任何其他函数:没有调用其他函数(既没有
baz
也没有bar
),没有查找值,等等。但是,已在函数内部检查语法
-