2014-11-13 4 views
2

Я думал, что у меня есть приличное понимание закрытия, а затем мой друг дал мне проблему, чтобы решить вопрос о закрытии (чего я не знал в то время). Вот блок кода:Путаница с закрытием и почему неправильные значения возвращаются

function fixMe() { 
    var numbers = []; 
    var i = 0; 
    for (; i < 10; i++) { 
    numbers[i] = function() { 
     return i; 
    }; 

    } 
    return numbers; 
} 

Так что, когда я называю:

var numbers = fixMe(); 
alert(numbers[2]()); 

Он всегда предупреждает 10, даже если бы я имел i в качестве параметра в функции fixMe().

Here это jsfiddle.

Решение он сказал мне, в конечном итоге существо:

function fixMe() { 
    var numbers = []; 
    var i = 0; 

    for (; i < 10; i++) { 
     numbers[i] = function (i) { 
      return function() { 
       return i; 
      }; 
     }(i); 
    } 

    return numbers; 
} 

var numbers = fixMe(); 
alert(numbers[2]()); 

Jsfiddle раствора. Я пробовал немало вещей, но не пришел к выводу, что мне нужны вложенные функции.

В настоящее время я не понимаю, почему первая функция вернет мне массив функций, который всегда возвращает 10. Я предполагаю, что это проблема закрытия? Во-вторых, почему одна и та же функция внутри другой функции решает проблему? Кажется, что требуется (i) в конце создания функции для решения, но он даже не компилируется, если вы добавите его без вложенной функции. Что именно он делает? Есть еще одно простое решение?

Это может быть много вопросов, но я чувствую, что они будут помогать мне в понимании закрытия в javascript, если им будет дан ответ.

ответ

4

Первая версия (сломанная) создает набор функций, которые все разделяют точно такую ​​же переменную i. То есть каждая функция в массиве сохраняет доступ к этой (единственной) переменной i. Это не копия от i, ее isi.

В конце цикла, какова величина этой переменной i? Это 10. Когда вы позже вызываете функции, это значение, которое вы возвращаете.

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

+0

Отлично, это объясняет это довольно хорошо. Еще один вопрос, что именно '(i)' делает в конце второй функции. Когда я удаляю его, он предупреждает о самой функции. –

+1

@JeremyW - это оператор '()', который вызывает функцию для вызова. Например, если у вас есть функция и вы хотите ее вызвать, вы пишете имя функции, а затем список аргументов в скобках: 'Math.sqrt (5)'. То же самое здесь: что перед этим '(i)'? Функция! Не функция * name *, а полная функция, созданная на месте. Так что '(i)' вызывает эту функцию для вызова. Иногда эта общая конструкция называется выражением с выведенной функцией (IIFE). – Pointy

Смежные вопросы