首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Javascript:在setTimeout中使用更改的全局变量

Javascript:在setTimeout中使用更改的全局变量
EN

Stack Overflow用户
提问于 2014-04-25 13:42:08
回答 3查看 15.9K关注 0票数 10

我正在开发Javascript,并使用firefox抓痕板来执行它。我有一个全局索引,我想在我的setTimeout (或任何异步执行的函数)中获取它。我不能使用Array.push作为数据顺序必须保持,就好像它是按顺序执行的。这是我的密码:-

代码语言:javascript
复制
function Demo() {
    this.arr = [];
    this.counter = 0;
    this.setMember = function() {
        var self = this;

        for(; this.counter < 10; this.counter++){
            var index = this.counter;
            setTimeout(function(){
                self.arr[index] = 'I am John!';
            }, 100);
        }
    };
    this.logMember = function() {
        console.log(this.arr);
    };
}

var d = new Demo();
d.setMember();

setTimeout(function(){
    d.logMember();
}, 1000);

在这里,我希望我的d.arr有0-9个索引,所有索引都有'I am John!',但是只有第9个索引有'I am John!'。我想,将this.counter保存到index局部变量将获得this.counter的快照。有人能帮我理解我的代码有什么问题吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-04-25 13:59:50

本例中的问题与JS中的范围有关。因为没有块作用域,所以它基本上相当于

代码语言:javascript
复制
this.setMember = function() {
    var self = this;
    var index;

    for(; this.counter < 10; this.counter++){
        index = this.counter;
        setTimeout(function(){
            self.arr[index] = 'I am John!';
        }, 100);
    }
};

当然,由于赋值是异步的,循环将运行到完成,将索引设置为9,然后函数在100 is后执行10次。

有几种方法可以做到这一点:

  1. IIFE (立即调用函数表达式)+ closurethis.setMember =函数(){ var self = this;var索引;for(;this.counter < 10;this.counter++){ index = this.counter;setTimeout(函数(i) {返回函数(){ self.arri = 'I‘m John!;})(索引),100;}; 在这里,我们创建一个匿名函数,立即用索引调用它,然后返回一个函数来完成赋值。index的当前值在闭包范围中保存为i,并且赋值是正确的。
  2. 类似于1,但使用单独的methodthis.createAssignmentCallback =函数(索引){ var self = this;返回函数() { self.arrindex = 'I是John!‘};};this.setMember =函数(){ var self = this;var索引;for(;this.counter < 10;this.counter++){ index = this.counter;this.counter 100;};};
  3. 使用Function.prototype.bind this.setMember = function() { for(;this.counter < 10;this.counter++){ setTimeout(函数(I){ this.arri = 'I是John!';}.bind(this,this.counter),100);};}; 因为我们所关心的只是将正确的i放入函数中,所以我们可以使用bind的第二个参数,它部分地应用了一个函数,以确保以后用当前索引调用它。我们还可以去掉self = this行,因为我们可以直接绑定调用函数的this值。当然,我们也可以去掉索引变量,直接使用this.counter,使其更加简洁。

就我个人而言,我认为第三个解决方案是最好的。它很短,很优雅,而且完全可以满足我们的需要。其他的一切都是为了完成语言当时所不支持的事情。因为我们有bind,所以没有更好的方法来解决这个问题。

票数 13
EN

Stack Overflow用户

发布于 2014-04-25 14:15:17

原因是在启动时间设置超时时,for循环已经完成,索引值为9,所以所有定时器基本上都在设置arr9。

票数 0
EN

Stack Overflow用户

发布于 2014-04-25 14:05:41

前面的答案是正确的,但提供的源代码是错误的,有一个错误的精灵代替了自我。解决办法有效。

另一种没有闭包的方法是将索引参数添加到setTimeout语句中的函数声明中。

代码语言:javascript
复制
function Demo() {
    this.arr = new Array();
    this.counter = 0;
    this.setMember = function() {
        var self = this;

        for(; this.counter < 10; this.counter++){
            var index = this.counter;
            setTimeout(function(){
                self.arr[index] = 'I am John!';
            }(index), 100);
        }
    };
    this.logMember = function() {
        console.log(this.arr);
    };
}

var d = new Demo();
d.setMember();

setTimeout(function(){
    d.logMember();
}, 1000);
票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23294903

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档