Let ключевое слово в цикле for
ECMAScript 6 let
должен обеспечивать область блока без головных болей. Может ли кто-нибудь объяснить, почему в приведенном ниже коде i
функция разрешает последнее значение из цикла (как и с var
) вместо значения текущей итерации?
"use strict";
var things = {};
for (let i = 0; i < 3; i++) {
things["fun" + i] = function() {
console.log(i);
};
}
things["fun0"](); // prints 3
things["fun1"](); // prints 3
things["fun2"](); // prints 3
В соответствии с MDN с помощью let
в цикле for
, который должен привязать переменную в области тела цикла. Вещи работают так, как я ожидаю, когда я использую временную переменную внутри блока. Почему это необходимо?
"use strict";
var things = {};
for (let i = 0; i < 3; i++) {
let index = i;
things["fun" + i] = function() {
console.log(index);
};
}
things["fun0"](); // prints 0
things["fun1"](); // prints 1
things["fun2"](); // prints 2
Я протестировал script с помощью Traceur и node --harmony
.
Ответы
Ответ 1
Ответ о косоглазиях больше не обновляется. В спецификация ECMA 6 указанное поведение таково, что в
for(let i;;){}
i
получает новое связывание для каждой итерации цикла.
Это означает, что каждое замыкание захватывает другой экземпляр i
. Таким образом, результат 012
является правильным результатом. Когда вы запустите это в Chrome v47 +, вы получите правильный результат. Когда вы запускаете его в IE11 и Edge, в настоящее время создается неправильный результат (333
).
Более подробную информацию об этой ошибке/функции можно найти в ссылках в этой странице;
Поскольку, когда используется выражение let
, каждая итерация создает новую лексическую область, привязанную к предыдущей области. Это имеет последствия для использования выражения let
, о котором сообщается здесь.
Ответ 2
Я передал этот код через Babel, чтобы мы могли понять поведение с точки зрения знакомого ES5:
for (let i = 0; i < 3; i++) {
i++;
things["fun" + i] = function() {
console.log(i);
};
i--;
}
Вот код, переданный на ES5:
var _loop = function _loop(_i) {
_i++;
things["fun" + _i] = function () {
console.log(_i);
};
_i--;
i = _i;
};
for (var i = 0; i < 3; i++) {
_loop(i);
}
Мы видим, что используются две переменные.
-
В внешней области i
есть переменная, которая изменяется по мере повторения.
-
Во внутренней области _i
есть уникальная переменная для каждой итерации. В конце концов будет три отдельных экземпляра _i
.
Каждая функция обратного вызова может видеть свой соответствующий _i
и может даже манипулировать им, если захочет, независимо от _i
в других областях.
(Вы можете подтвердить, что есть три разных _i
, делая console.log(i++)
внутри обратного вызова. Изменение _i
в предыдущем обратном вызове не влияет на вывод последующих обратных вызовов.)
В конце каждой итерации значение _i
копируется в i
. Поэтому изменение уникальной внутренней переменной во время итерации повлияет на внешнюю итерированную переменную.
Хорошо видеть, что ES6 продолжил давнюю традицию WTFJS.
Ответ 3
IMHO - программисты, которые впервые внедрили этот LET (создавая результаты своей первоначальной версии), сделали это правильно в отношении здравомыслия; они могут не взглянуть на спецификацию во время этой реализации.
Имеет смысл, что используется одна переменная, но привязана к циклу for. Тем более, что вы можете свободно изменять эту переменную в зависимости от условий внутри цикла.
Но подождите - вы можете изменить переменную цикла. WTFJS!! Однако, если вы попытаетесь изменить его во внутренней области, он не будет работать сейчас, потому что это новая переменная.
Мне не нравится то, что я должен сделать. Чтобы получить то, что я хочу (единственная переменная, которая является локальной для for):
{
let x = 0;
for (; x < length; x++)
{
things["fun" + x] = function() {
console.log(x);
};
}
}
Где изменить более интуитивную (если мнимую) версию для обработки новой переменной на итерацию:
for (let x = 0; x < length; x++)
{
let y = x;
things["fun" + y] = function() {
console.log(y);
};
}
Ясно, что мое намерение с переменной y есть.. Или было бы, если бы SANITY управляла вселенной.
Итак, ваш первый пример теперь работает в FF; он производит 0, 1, 2. Вы можете решить проблему. Я вызываю проблему WTFJS.
пс. Моя ссылка на WTFJS от JoeyTwiddle выше; Это похоже на мему, которую я должен был знать до сегодняшнего дня, но сегодня было замечательное время, чтобы изучить его.