setInterval 覆盖其他 setIntervals

setInterval overriding others setIntervals

本文关键字:setIntervals 其他 覆盖 setInterval      更新时间:2023-09-26

我正在尝试创建多个 setInterval 并存储它们(稍后清除),但是当我这样做时,最后一个 setInterval 会覆盖上一个,为每个前一个 setInterval 执行一次,但内容相同。

具有奇怪行为的代码片段:

var timeoutFunctions= {};
function log_on_console(text){
  console.log(' > > > inside function : '+text)
}
$( document ).ready(function() {
    for (i = 0; i < 5; i++) {
      console.log(' > > > before function : '+i)
      timeoutFunctions[i] = setInterval(function(){log_on_console(i)}, 2000);
    }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

控制台上的输出是:

" > > > before function : 0" js:21:6
" > > > before function : 1" js:21:6
" > > > before function : 2" js:21:6
" > > > before function : 3" js:21:6
" > > > before function : 4" js:21:6
" > > > inside function : 5" (5) js:16:2 //(this one is the "problem")

我正在尝试这样的东西:

" > > > before function : 0" js:21:6
" > > > before function : 1" js:21:6
" > > > before function : 2" js:21:6
" > > > before function : 3" js:21:6
" > > > before function : 4" js:21:6
" > > > inside function : 0" js:16:2 
" > > > inside function : 1" js:16:2 
" > > > inside function : 2" js:16:2 
" > > > inside function : 3" js:16:2 
" > > > inside function : 4" js:16:2 

那么,为什么最后一个setInterval(function(){log_on_console(i)}, 2000)会覆盖前四个呢?

这里的函数:

timeoutFunctions[i] = setInterval(function(){log_on_console(i)}, 2000);

。具有对 i 变量的持久引用,而不是创建函数时其值的副本。因此,它使用i调用时具有的值。

如果要在创建函数时将i的值刻录到函数中,可以使用Function#bind

timeoutFunctions[i] = setInterval(function(val){log_on_console(val)}.bind(null, i), 2000);

或者更直接地作为您的匿名函数,只需调用log_on_console

timeoutFunctions[i] = setInterval(log_on_console.bind(null, i), 2000);

Function#bind返回一个函数,该函数在调用时将调用原始函数,this设置为您bind的第一个参数,并传递任何其他参数。由于您的函数不使用this,我只是对该参数使用了null。例如:

function foo(a) {
    console.log("a = " + a);
}
var f = foo.bind(null, 1);
f();

向我们展示:

a = 1

旁注:你的代码正在成为隐式全局的恐怖的牺牲品,因为你没有在任何地方声明i

use closure()

$(document).ready(function () {
    for (var i = 0; i < 5; i++) {
        console.log(' > > > before function : ' + i)
        (function (curent) {
            timeoutFunctions[curent] = setInterval(function () {
                log_on_console(curent)
            }, 2000);
        })(i)
    }
});