В Дон 't Know Javascript, 1/3 IIFE описываются как не закрывающиеся сами по себе, а только в том случае, если они выполняются за пределами своей лексической области:
В главе 3 был представлен паттерн IIFE. Хотя часто говорят, что IIFE (отдельно) является примером наблюдаемого закрытия, я бы несколько не согласился с нашим определением, приведенным выше.
Этот код «работает», но это не строго наблюдение за закрытием. Почему? Потому что функция (которую мы здесь назвали «IIFE») не выполняется вне своей лексической области видимости. Он по-прежнему вызывается прямо там, в той же области, в которой он был объявлен (охватывающая / глобальная область, которая также содержит a). a можно найти с помощью обычного поиска в лексической области видимости, а не с помощью замыкания.
var a = 2;
(function IIFE(){ // not actually a "closure"
console.log( a );
})();
В этом сообщении SO следующий фрагмент был приведен в качестве примера закрытия:
for (var i = 0; i < someVar.length; i++)
(function (i) {
window.setTimeout(function () {
alert("Value of i was "+i+" when this timer was set" )
}, 10000);
})(i);
Я пытаюсь понять это с точки зрения определения закрытия (как определено в эта средняя статья):
Чтобы использовать замыкание, просто определите функцию внутри другой функции и откройте ее. Чтобы открыть функцию, верните ее или передайте другой функции. ...
Внутренняя функция будет иметь доступ к переменным во внешней области функции даже после возврата внешней функции.
Я понимаю, что закрытие - это "функция с отслеживанием состояния", и что это
способ «запомнить» и продолжить доступ к области видимости функции (ее переменным) даже после того, как функция завершила выполнение.
Итак, в этом примере я вижу, что i
цикла запоминается при передаче в закрывающий IIFE.
Мой вопрос:
Где происходит «переход к другой функции или возврат»? Я предполагаю, что IIFE может запоминать внешнее значение цикла i
for на каждой итерации, потому что IIFE передается в окно?
В принципе, я понимаю, что закрытие определяется как запоминание значения внешней области после того, как сборщик мусора очищает эту внешнюю область, и что его использование заключается в том, чтобы раскрыть закрытие, возвращая его и обращаясь к нему за пределами его лексической области видимости. Это правильно? Так где же происходит «доступ к нему за пределами лексической области»?
let plus3 = (x => y => x + y)(3);
. Здесь переменнаяx
закрыта. Когда вы вызываете его со значением 3, он возвращает функцию, которая принимает другой аргумент y и добавляет к нему 3. - person Jared Smith   schedule 17.07.2017window
не имеет к этому никакого отношения, все анонимные функции, переданные вsetTimeout
, закрываются по переменнойi
в цикле. - person Jared Smith   schedule 17.07.2017setTimeout
, закрываются над переменнойi
, почему это не сохраняетсяi
? Обертка IIFE ((function (i) { ... })(i)
) создает более закрытую область, которая каким-то образом сохраняетi
после завершения цикла. Это потому, что упаковкаIIFE
выполняется в другом объеме? - person Growler   schedule 17.07.2017(function (i) { ... })(i)
целью этого IIFE является создание локальной (аргументной) переменной, чтобы каждый из обратных вызововsetTimeout
ссылался на другую локальную переменную с именемi
вместо того же глобальногоi
. Функция, переданная вsetTimeout
clsoes, вместоi
, созданного аргументом с именемi
в окружающем IIFE. - person apsillers   schedule 17.07.2017i
сохраняется. Это должно быть, потому чтоsetTimeout
делает выполнение асинхронным. Без IIFE для создания замыканияi
будет любым значением при фактическом вызове обратного вызова, в этом случае он будетsomeVar.length - 1
снова и снова, а не увеличивать значения. Вставьтеfor (var i=0; i<10; ++i) setTimeout(function() { console.log(i) })
в консоль. - person Jared Smith   schedule 17.07.2017for loop
(в этот моментi
===someVar.length-1
). Когда стек цикла событий очищен,setTimeout
выполняется и возвращается ... безIIFE
, анонимная функцияsetTimeout
все еще закрывается черезi
, но уже после завершения цикла событий.IIFE
вызывается для каждой итерацииi
и создает локальную переменную значенияi
. - person Growler   schedule 17.07.2017IIFE
или без него анонимная функцияsetTimeout
по-прежнему закрывается болееi
. Мы просто хотим закрыть правильный локальныйi
из выполненногоIIFE
- person Growler   schedule 17.07.2017