gpt4 book ai didi

Javascript:在 setTimeout 中使用不断变化的全局变量

转载 作者:数据小太阳 更新时间:2023-10-29 05:57:57 24 4
gpt4 key购买 nike

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

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 个索引有 “我是约翰!”。我想,将 this.counter 保存到 index 局部变量中将获取 this.counter 的快照。任何人都可以帮助我了解我的代码有什么问题吗?

最佳答案

本例中的问题与 JS 中的作用域有关。由于没有 block 范围,它基本上等同于

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。然后该函数将在100ms后执行10次。

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

  1. IIFE(立即调用函数表达式)+闭包

    this.setMember = function() {
    var self = this;
    var index;

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

    这里我们创建了一个匿名函数,立即用索引调用它,然后返回一个函数来做赋值。 index的当前值在闭包作用域中保存为i且赋值正确

  2. 与1类似,但使用不同的方法

    this.createAssignmentCallback = function (index) {
    var self = this;
    return function () {
    self.arr[index] = 'I am John!';
    };
    };

    this.setMember = function() {
    var self = this;
    var index;

    for(; this.counter < 10; this.counter++){
    index = this.counter;
    setTimeout(this.createAssignmentCallback(index), 100);
    }
    };
  3. 使用 Function.prototype.bind

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

    因为我们关心的是将正确类型的 i 放入函数中,我们可以使用 bind 的第二个参数,它部分地将函数应用于确保稍后使用当前索引调用它。我们也可以去掉 self = this 行,因为我们可以直接绑定(bind)被调用函数的 this 值。我们当然也可以去掉index变量,直接使用this.counter,更加简洁。

个人认为第三种方案最好。它简短、优雅,并且正是我们所需要的。其他一切都更像是一种黑客技术,可以完成当时该语言不支持的事情。由于我们有 bind,没有更好的方法来解决这个问题。

关于Javascript:在 setTimeout 中使用不断变化的全局变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23294903/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com