jQuery .each和setTimeout不能很好地协同工作

问题描述:

为什么这会返回undefined为所有ID?jQuery .each和setTimeout不能很好地协同工作

var time = 200; 

$('.block').each(function() { 
    setTimeout(function() { 
     console.log($(this).attr('id')); 
     }, time); 

    time += 200; 
}); 

但是这返回的ID就好了?

var time = 200; 

$('.block').each(function() { 
    console.log($(this).attr('id')); 

    setTimeout(function() { 
     }, time); 

    time += 200; 
}); 

我试图创造一种在时间效应在一个沸腾的,这是推动我疯了

this的CA内的值llback(全局对象)与外部作用域(它是当前元素)不一样。使用以下方法来参考关闭到正确的值:

$('.block').each(function() { 
    var that = $(this); 
    setTimeout(function() { 
     console.log(that.attr('id')); 
    }, time); 
    time += 200; 
}); 

这工作,因为传递给setTimeout的功能是保持可访问其词法范围声明的变量(包括that)封闭。

一般这里课是,this的函数内的值被动态地确定和功能是如何执行上完全取决于:

  • jQuery的执行外功能和显式地设定this到当前元素(使用call/apply)。
  • 浏览器在全局环境中执行内部函数,这就是为什么this的值为window的原因。这个简单的测试表明,最后一点:

    setTimeout(function() { 
        alert(this === window); // true 
    }, 1000) 
    

在现代浏览器中,上述的解决的办法是使用bind

$('.block').each(function() { 
    setTimeout(function() { 
     console.log($(this).attr('id')); 
    }.bind(this), time); 
    time += 200; 
}); 

setTimeout运行的this值发生了变化。为了解决这个问题,你可以在你的.each()循环缓存this值,使之在提供给匿名函数您setTimeout

var time = 200; 
$('.block').each(function() { 
    var $this = $(this); 
    setTimeout(function() { 
     console.log($this.attr('id')); 
     }, time); 

    time += 200; 
}); 

这里是一个演示:http://jsfiddle.net/FRzWc/

此外,如果你想提高你的循环性能则颇有几分使用$.each(),而不是.each()

var time = 200; 
$.each($('.block'), function() { 
    var $this = $(this); 
    setTimeout(function() { 
     $this.text($this.attr('id')); 
     console.log($this.attr('id')); 
     }, time); 

    time += 200; 
});