抱歉,原本的写法有错。
函数被 setTimeout 呼叫的时候,this 会被设定成 window,
所以呼叫有用到 this 的函数就会出问题。
这里比较常见的作法是使用 closure 处理:
var audios = [audio1, audio2, audio3];
var time = [0, 500, 1000];
for(var i=0; i<3; i++) {
(function(index){
setTimeout(function(){
audios[index].play();
}, time[i]);
})(i);
}
这里直接用 audios[i].play() 的话会有错,
因为离开循环后 i 的值固定是 3,
setTimeout 的时间到时就会变成执行audios[3].play()。
用 closure 包起来后,
外面的 function 每次执行会产生一个新的环境,一共 3 个。
每个环境有自己的 index,即使 i 改变了,index也不会受到影响。
另外也可以用 bind:
var audios = [audio1, audio2, audio3];
var time = [0, 500, 1000];
for(var i=0; i<3; i++) {
setTimeout(audios[i].play.bind(audios[i]), time[i]);
}
因为懒了所以就不解释了XD
※ 引述《iamshuichi (vincent)》之铭言:
: <html>
: <audio id="audio1" src="1.wav"></audio>
: <audio id="audio2" src="2.wav"></audio>
: <audio id="audio3" src="3.wav"></audio>
: <button onclick="play()">Start</button>
: <script>
: var play = function() {
: var audioPlay=[audio1.play, audio2.play, audio3.play];
: var time=[0, 500, 1000];
: for (var i=0; i<3; i++) {
: setTimeout(audioPlay[i], time[i]);
: }
: }
: </script>
: </html>
: 您的范例我看到了,是可以正常执行的
: 但是我套用上去就不行了
: 到底是发生了什么事???
: >_<
: ※ 引述《Kenqr (function(){})()》之铭言:
: : var audioPlay = [audio1.play, audio2.play, audio3.play];
: : var time = [0, 500, 1000];
: : for(var i=0; i<3; i++) {
: : setTimeout(audioPlay[i], time[i]);
: : }
: : 实际可执行的范例:
: : https://jsfiddle.net/hzrw429z/1/
: : 第一行的 audio1.play() 拿掉括号改成 audio1.play,
: : 因为这个阵列里要放的是函数而不是函数的执行结果。
: : 写成 audio1.play() 会在执行到宣告阵列这行时就播放了,函数也没存进阵列里。
: : setTimeout 这行,"audioPlay[i]" 拿掉双引号改成 audioPlay[i]。
: : 因为 setTimeout 传入字串时,是把字串内容当成函数内容执行。
: : 原本的写法会在时间到时取出 audioPlay 阵列第 i 项的值,
: : 取出后没有做任何动作,所以什么事都没发生。
: : 修正的写法会在呼叫 setTimeout 函数前先取得 audioPlay 的第 i 项,
: : 取得的东西是一个函数,当成参数传给 setTimeout。
: : 所以 3 次呼叫 setTimeout 相当于:
: : setTimeout(audio1.play, 0);
: : setTimeout(audio2.play, 500);
: : setTimeout(audio3.play, 1000);
: : 时间到时可以正确的分别执行 3 个函数。
: : 这个情况不需要使用 IIFE,
: : 因为 audioPlay[i] 是在呼叫 setTimeout 之前就已经取值了。
: : setTimeout 在时间到时,呼叫第一个参数的函数时已经不会用到 i,
: : 所以即使离开循环后 i 的值固定是 3,对我们也没有影响。