我有以下javascript代码:
var Person = [['John', 0, 0, 0],['Chris', 1, 0, 0]];
for (i = 0; i < Person.length; i++ )
{
someObj.myMethod(Person[i][0], function (object) {
console.log(i); //this prints 2, I want 0 and 1 as per the loop
//here I want to access other members of Person[i] array, like Person[i][1], Person[i][2] and Person[i][3]
//but these console.log() print 'undefined' because i = 2 !!
console.log(Person[i][1]);
console.log(Person[i][2]);
console.log(Person[i][3]);
});
}
在我的myMethod()里面调用的匿名函数里面,i的值是'2'。请建议如何在for循环的第一个循环中获得i = 0,然后在第二个循环中获得1。
答案 0 :(得分:3)
使用闭包,这是一个解决方案:
var Person = [['John', 0, 0, 0],['Chris', 1, 0, 0]];
for (x = 0; x < Person.length; x++ )
{
(function(i){ //We add a closure
someObj.myMethod(Person[i][0], function (object) {
console.log(i);
console.log(Person[i][1]);
console.log(Person[i][2]);
console.log(Person[i][3]);
});
})(x); //Call the closure function with the value of the counter
}
我将原始计数器更改为x
以使其更易于理解(因此您不要将该变量与原始i
混淆),但如果它仍然命名为i
,它将会工作也是。
这样,每个循环周期都有自己的变量x
( not shared ),因此它不会被for循环覆盖,导致问题({{ 1}}共享):)
干杯
答案 1 :(得分:2)
你有一个漏洞closure。试试这个:
var Person = [['John', 0, 0, 0],['Chris', 1, 0, 0]];
for (i = 0; i < Person.length; i++ )
{
doIt(i);
}
function doIt(i) {
someObj.myMethod(Person[i][0], function (object) {
console.log(i); //this prints 2, I want 0 and 1 as per the loop
//here I want to access other members of Person[i] array, like Person[i][1], Person[i][2] and Person[i][3]
//but these console.log() print 'undefined' because i = 2 !!
console.log(Person[i][1]);
console.log(Person[i][2]);
console.log(Person[i][3]);
});
}
基本上,你原来的内部匿名函数正被传递到其他地方以便稍后执行,在这个阶段,i
变量在for循环中已经增加到2
(它们实际上是在引用一份i
)。 Javascript是函数作用域,所以引入一个新函数和它自己的参数来捕获i
的特定值,你可以将你的匿名函数与for循环中的共享计数器分离。
请注意,您还可以使函数(在我的示例中为doIt
)立即执行匿名函数,如Edgar has,这意味着没有其他人可以调用逻辑上的私有闭包函数(尽管它可以说是让那些不熟悉javascript闭包的人阅读有点困难。)
答案 2 :(得分:2)
执行回调时完全 如果它们立即执行 ,则在循环运行时,值将如您所愿。以下输出0
和1
:
var someObj = {
myMethod: function(person, callback) {
callback();
}
}
var Person = [['John', 0, 0, 0],['Chris', 1, 0, 0]];
for (i = 0; i < Person.length; i++ )
{
someObj.myMethod(Person[i][0], function (object) {
console.log(i);
});
}
但是,如果回调是存储并稍后执行,那么(这是理解的关键)每个存储的回调都关闭了相同的变量{{循环完成后,该变量的值为i
。
换句话说,闭包在变量本身上,而不是在创建闭包时的值。正如其他人所说,使用接收2
作为参数的包装函数可以轻松解决此问题。这会为每个要关闭的回调创建一个 new 变量。
这是一个人为的例子:
i
你的另一个选择是将var someObj = {
callbacks: [],
myMethod: function(person, callback) {
someObj.callbacks.push(callback);
}
}
var Person = [['John', 0, 0, 0],['Chris', 1, 0, 0]];
for (i = 0; i < Person.length; i++ )
{
(function(i) {
someObj.myMethod(Person[i][0], function (object) {
console.log(i);
});
})(i);
}
someObj.callbacks[0]();
someObj.callbacks[1]();
的元素传递给你的回调,而不是它们在数组中的索引。
答案 3 :(得分:1)
处理闭包问题的另一种方法是创建局部变量并将其传递给函数。
var Person = [['John', 0, 0, 0],['Chris', 1, 0, 0]];
for (var i = 0; i < Person.length; i++ ) {
var x = i;
someObj.myMethod(Person[x][0], function (object) {
console.log(Person[x][1]);
console.log(Person[x][2]);
console.log(Person[x][3]);
});
}