繁体   English   中英

如何在匿名函数调用中获取外部循环索引?

[英]How to get outer loop index inside anonymous function call?

我有以下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。

有了一个闭包,这个解决方案:

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不共享 ),所以它不会被for循环覆盖,导致问题( i被共享):)

干杯

你有一个漏洞关闭 尝试这个:

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一样立即执行匿名函数,这意味着没有其他人可以调用逻辑上的私有闭包函数(尽管它可能会让某些人更难读用于javascript闭包)。

完全取决于何时执行回调。 如果它们立即执行,则在循环运行时,值将如您所愿。 以下输出01

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

换句话说, 闭包在变量本身上,而不是在创建闭包时的值 正如其他人所说,使用包含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]();

在您的情况下,另一个选项是将Person的元素传递给您的回调,而不是它们在数组中的索引。

处理闭包问题的另一种方法是创建局部变量并将其传递给函数。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM