简体   繁体   English

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

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

I have the following javascript code : 我有以下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]);
    });
}

Inside the anonymous function called inside my myMethod(), value of i is '2'. 在我的myMethod()里面调用的匿名函数里面,i的值是'2'。 Please suggest how to get i = 0 in first cycle of for loop and then 1 in the second loop. 请建议如何在for循环的第一个循环中获得i = 0,然后在第二个循环中获得1。

With a closure, this a solution: 有了一个闭包,这个解决方案:

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
}

I changed the original counter to x to make it more understandable (so you dont confuse that variable with the original i ), but if it keeps named also i , it will work, too. 我将原始计数器更改为x以使其更容易理解(因此您不要将该变量与原始i混淆),但如果它仍然命名为i ,它也会起作用。

This way, each loop cycle has it's own variable x ( not shared ), so it doesn't get overwritten by the for loop, which was causing the problem ( i was shared) :) 这样,每个循环周期都有自己的变量x不共享 ),所以它不会被for循环覆盖,导致问题( i被共享):)

Cheers 干杯

You have a leaky closure . 你有一个漏洞关闭 Try this: 尝试这个:

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

Basically, your original inner anonymous function is being passed elsewhere to be executed later, by which stage the i variable has already been incremented to 2 in the for loop (they're effectively referencing the one copy of i ). 基本上,你原来的内部匿名函数正被传递到别处以便稍后执行,在哪个阶段, i变量已经在for循环中递增到2 (它们实际上引用了i的一个副本)。 Javascript is function scoped, so introducing a new function with it's own parameter to trap the specific value of i , you can decouple your anonymous function from the shared counter in the for loop. Javascript是函数作用域,所以引入一个新函数和它自己的参数来捕获i的特定值,你可以将你的匿名函数与for循环中的共享计数器分离。

Note that you can also make the function ( doIt in my example) an immediately executing anonymous function like Edgar has , which means that no one else can call the logically private closure function (though it arguably makes it a little harder to read to someone not used to javascript closures). 请注意,您也可以使函数(在我的示例中为doIt )像Edgar一样立即执行匿名函数,这意味着没有其他人可以调用逻辑上的私有闭包函数(尽管它可能会让某些人更难读用于javascript闭包)。

It depends entirely on when the callbacks are executed. 完全取决于何时执行回调。 If they are executed immediately , as the loop is running, then the values will be as you expect. 如果它们立即执行,则在循环运行时,值将如您所愿。 The following outputs 0 and 1 : 以下输出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); 
    });
}

However, if the callbacks are stored and executed later, then (and this is the key thing to understand) each callback stored has closed over the same variable i and that variable's value is 2 after the loop has completed. 但是,如果稍后存储并执行回调,那么(这是理解的关键)每个回调存储已关闭相同的变量i并且在循环完成后该变量的值为2

In other words, the closure is over the variable itself, not its value at the time the closure is created . 换句话说, 闭包在变量本身上,而不是在创建闭包时的值 As others have stated, this problem is easily solved using a wrapper function that receives i as an argument. 正如其他人所说,使用包含i作为参数的包装函数可以很容易地解决这个问题。 This creates a new variable for each callback to close over. 这会为每个要关闭的回调创建一个变量。

Here's a contrived example: 这是一个人为的例子:

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

Another option in your case is to pass the elements of Person to your callback, instead of their index in the array. 在您的情况下,另一个选项是将Person的元素传递给您的回调,而不是它们在数组中的索引。

Another way to deal with closure issue that you have is to create local variable and pass it to your function. 处理闭包问题的另一种方法是创建局部变量并将其传递给函数。

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