Доступ к скопированной целочисленной переменной в javascript анонимном методе - PullRequest
7 голосов
/ 21 ноября 2011

Я разработчик C # и привык к тому, как замыкания работают в C #. В настоящее время я должен работать с анонимными функциями JavaScript и столкнуться с проблемой следующего фрагмента:

    function ClosureTest() {
    var funcArray = new Array();

    var i = 0;
    while (i < 2) {
        var contextCopy = i;

        funcArray[i] = function() { alert(contextCopy); return false; };

        i++;
    }

    funcArray[0]();
    funcArray[1]();
}

Я ожидаю, что первый funcArray() вызов скажет 0, а второй скажет 1. Тем не менее, они оба говорят 1. Как это возможно?

Написав var contextCopy = i, я удостоверяюсь, что создаю копию переменной i. Затем в каждой итерации цикла я создаю совершенно новый указатель на функцию. Каждая функция ссылается на свою собственную копию i, которая является contextCopy. Однако обе созданные функции по какой-то причине ссылаются на одну и ту же переменную contextCopy.

Как это работает в JavaScript?

Ответы [ 3 ]

12 голосов
/ 21 ноября 2011

JavaScript имеет лексические замыкания, а не замыкания.Даже если вы назначаете i для contextCopy, contextCopy сам по себе является лексическим членом ClosureTest (который отличается от C #, где {} дает вам новый блок с областью видимости).Попробуйте это:

while (i < 2) {
    funcArray[i] = (function(value) { 
        return function(){ alert(value); return false; }
    })(i);
    i++;
}
8 голосов
/ 21 ноября 2011

Фигурные скобки ({}) в JavaScript не захватывают переменные, как в C #.

Только замыкания (функции) вводят новую область видимости и захватывают переменные.

var i = 0;
while (i < 2) {
  var contextCopy = i;
  ...
}

фактически интерпретируется как:

var i, contextCopy;
i = 0;
while (i < 2) {
  contextCopy = i;
  ...
}

Чтобы получить копию переменной, вам нужно обернуть код закрытием:

var i;
i = 0;
while (i < 2) {
  (function (contextCopy) {
  ...
  }(i));
}
0 голосов
/ 21 ноября 2011

Вы не создаете копию переменной i.Вместо этого вы делаете эту переменную GC-зависимой от замыканий, которые ее используют.Это означает, что при выходе из цикла while переменная i продолжает жить в своем последнем состоянии (1), и оба замыкания ссылаются на него.

Другой способ выразить это: закрытие переменной не копирует ее вваше закрытие (не имеет большого смысла для объектов), оно просто делает ваше закрытие ссылкой на переменную и гарантирует, что эта переменная не GCed, пока закрытие не будет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...