# Что происходит в этом коде Функция `makeArmy` делает следующее:
  1. Создаёт пустой массив `shooter`: ```js var shooters = []; ```
  2. В цикле заполняет массив элементами через `shooter.push`. При этом каждый элемент массива -- это функция, так что в итоге после цикла массив будет таким: ```js //+ no-beautify shooters = [ function () { alert(i); }, function () { alert(i); }, function () { alert(i); }, function () { alert(i); }, function () { alert(i); }, function () { alert(i); }, function () { alert(i); }, function () { alert(i); }, function () { alert(i); }, function () { alert(i); } ]; ``` Этот массив возвращается из функции.
  3. Вызов `army[5]()` -- это получение элемента массива (им будет функция), и тут же -- её запуск.
# Почему ошибка Вначале разберемся, почему все стрелки выводят одно и то же значение. В функциях-стрелках `shooter` отсутствует переменная `i`. Когда такая функция вызывается, то `i` она берет из внешнего `LexicalEnvironment`. Чему же будет равно это значение `i`? К моменту вызова `army[0]()`, функция `makeArmy` уже закончила работу. Цикл завершился, последнее значение было `i=10`. В результате все функции `shooter` получают из внешнего лексического кружения это, одно и то же, последнее, значение `i=10`. Попробуйте исправить проблему самостоятельно. # Исправление (3 варианта) Есть несколько способов исправить ситуацию.
  1. **Первый способ исправить код - это привязать значение непосредственно к функции-стрелку:** ```js //+ run function makeArmy() { var shooters = []; for (var i = 0; i < 10; i++) { *!* var shooter = function me() { alert( me.i ); }; shooter.i = i; */!* shooters.push(shooter); } return shooters; } var army = makeArmy(); army[0](); // 0 army[1](); // 1 ``` В этом случае каждая функция хранит в себе свой собственный номер. Кстати, обратите внимание на использование Named Function Expression, вот в этом участке: ```js ... var shooter = function me() { alert( me.i ); }; ... ``` Если убрать имя `me` и оставить обращение через `shooter`, то работать не будет: ```js for (var i = 0; i < 10; i++) { var shooter = function() { *!* alert( shooter.i ); // вывести свой номер (не работает!) // потому что откуда функция возьмёт переменную shooter? // ..правильно, из внешнего объекта, а там она одна на всех */!* }; shooter.i = i; shooters.push(shooter); } ``` Вызов `alert(shooter.i)` при вызове будет искать переменную `shooter`, а эта переменная меняет значение по ходу цикла, и к моменту вызову она равна последней функции, созданной в цикле. Если использовать Named Function Expression, то имя жёстко привязывается к конкретной функции, и поэтому в коде выше `me.i` возвращает правильный `i`.
  2. **Другое, более продвинутое решение -- использовать дополнительную функцию для того, чтобы "поймать" текущее значение `i`**: ```js //+ run function makeArmy() { var shooters = []; for (var i = 0; i < 10; i++) { *!* var shooter = (function(x) { return function() { alert( x ); }; })(i); */!* shooters.push(shooter); } return shooters; } var army = makeArmy(); army[0](); // 0 army[1](); // 1 ``` Посмотрим выделенный фрагмент более внимательно, чтобы понять, что происходит: ```js var shooter = (function(x) { return function() { alert( x ); }; })(i); ``` Функция `shooter` создана как результат вызова промежуточного функционального выражения `function(x)`, которое объявляется -- и тут же выполняется, получая `x = i`. Так как `function(x)` тут же завершается, то значение `x` больше не меняется. Оно и будет использовано в возвращаемой функции-стрелке. Для красоты можно изменить название переменной `x` на `i`, суть происходящего при этом не изменится: ```js var shooter = (function(i) { return function() { alert( i ); }; })(i); ``` **Кстати, обратите внимание -- скобки вокруг `function(i)` не нужны**, можно и так: ```js var shooter = function(i) { // *!*без скобок вокруг function(i)*/!* return function() { alert( i ); }; }(i); ``` Скобки добавлены в код для лучшей читаемости, чтобы человек, который просматривает его, не подумал, что `var shooter = function`, а понял что это вызов "на месте", и присваивается его результат.
  3. **Еще один забавный способ - обернуть весь цикл во временную функцию**: ```js //+ run function makeArmy() { var shooters = []; *!* for (var i = 0; i < 10; i++)(function(i) { var shooter = function() { alert( i ); }; shooters.push(shooter); })(i); */!* return shooters; } var army = makeArmy(); army[0](); // 0 army[1](); // 1 ``` Вызов `(function(i) { ... })` обернут в скобки, чтобы интерпретатор понял, что это `Function Expression`. Плюс этого способа - в большей читаемости. Фактически, мы не меняем создание `shooter`, а просто обертываем итерацию в функцию.