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

时间:2012-02-10 18:29:24

标签: javascript jquery css

为什么这个ID的返回未定义?

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;
});

我正在尝试一次一个地创造一种冒泡效果,这让我发疯了

2 个答案:

答案 0 :(得分:5)

回调内的this(全局对象)的值与外部作用域(当前元素)的值不同。使用以下命令关闭对正确值的引用:

$('.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;
});

答案 1 :(得分:1)

setTimeout运行时,this的值已更改。要解决此问题,您可以在this循环中缓存.each()值,以便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;
});