Javascript:在setTimeout中使用更改全局变量
我正在使用Javascript:在setTimeout中使用更改全局变量,javascript,Javascript,我正在使用Javascript并使用firefox scratchpad执行它。我有一个全局索引,我想在我的setTimeout(或异步执行的任何函数)中获取它。我不能使用数组。按,因为数据的顺序必须保持为按顺序执行。这是我的密码:- function Demo() { this.arr = []; this.counter = 0; this.setMember = function() { var self = this; for(;
Javascript
并使用firefox scratchpad执行它。我有一个全局索引,我想在我的setTimeout
(或异步执行的任何函数)中获取它。我不能使用数组。按,因为数据的顺序必须保持为按顺序执行。这是我的密码:-
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);
函数演示(){
this.arr=[];
这个计数器=0;
this.setMember=函数(){
var self=这个;
对于(;this.counter<10;this.counter++){
var指数=这个计数器;
setTimeout(函数(){
self.arr[index]=“我是约翰!”;
}, 100);
}
};
this.logMember=函数(){
console.log(this.arr);
};
}
var d=新的Demo();
d、 setMember();
setTimeout(函数(){
d、 logMember();
}, 1000);
在这里,我希望我的
d.arr
有0-9个索引,所有索引都有“我是约翰!”代码>,但只有第9个索引有“我是约翰!”代码>。我想,将this.counter
保存到index
局部变量中,将拍摄this.counter
的快照。有人能帮我理解我的代码有什么问题吗?设置超时
没有您所期望的索引的快照。所有超时都会将索引视为最终迭代,因为您的循环在超时触发之前完成。您可以将其包装在闭包中并传入索引,这意味着闭包中的索引将受到保护,不受对全局索引的任何更改的影响
(function(index){
setTimeout(function(){
self.arr[index] = 'I am John!';
}, 100);
})(index);
本例中的问题与JS中的作用域有关。
因为没有块作用域,所以它基本上相当于
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);
}
};
使用
this.setMember=function(){
对于(;this.counter<10;this.counter++){
设置超时(功能(i){
这个。啊[我]=“我是约翰!”;
}.bind(这个,这个计数器),100);
}
};
由于我们所关心的只是将正确类型的i
放入函数中,因此我们可以使用bind
的第二个参数,该参数部分应用函数,以确保稍后使用当前索引调用该函数。我们还可以去掉self=this
行,因为我们可以直接绑定调用的函数的this
值。当然,我们也可以去掉索引变量,直接使用this.counter,使其更加简洁
我个人认为第三种解决方案是最好的。
它短而优雅,完全符合我们的需要。
其他一切都是为了完成该语言当时不支持的事情而进行的黑客攻击。
因为我们有bind
,所以没有更好的方法来解决这个问题。前面的答案是正确的,但是提供的源代码是错误的,在self中输入了一个错误的elf。这些解决方案是有效的
另一种没有闭包的方法是只将索引参数添加到setTimeout语句中的函数声明中
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);
函数演示(){
this.arr=新数组();
这个计数器=0;
this.setMember=函数(){
var self=这个;
对于(;this.counter<10;this.counter++){
var指数=这个计数器;
setTimeout(函数(){
self.arr[index]=“我是约翰!”;
}(指数),100);
}
};
this.logMember=函数(){
console.log(this.arr);
};
}
var d=新的Demo();
d、 setMember();
setTimeout(函数(){
d、 logMember();
}, 1000);
原因是,在启动settimeout时,for循环已完成执行,索引值为9,因此所有计时器基本上都在设置arr[9]。这是不正确的,不起作用。您将直接调用函数,而不是在100毫秒后。您将向它传递一个参数,但它将被丢弃。然后从外部范围中获取索引
,这很好,因为它是同步执行的。100毫秒后,什么也没有发生。如果你在firefow草稿行中剪切粘贴代码,它将显示“我是约翰”,这是第一个问题。我只是想帮助解决这个错误。如果我有两个参数(我不应该传递)而不是索引呢?例如:函数(结果、状态)
。那么我们如何使用bind呢?基本上就像Function.prototype.call
一样使用它。所以您需要执行fn.bind(context、firstParam、secondParam、thirdParam)
等等。
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);
}
};
this.setMember = function() {
for(; this.counter < 10; this.counter++){
setTimeout(function(i){
this.arr[i] = 'I am John!';
}.bind(this, this.counter), 100);
}
};
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);