Замыкание (JS) требует функции внутри функции

У меня есть небольшая трудность с присущей концепцией закрытия. Я получаю основную идею, но вот что: я думал, что технически там есть "закрытие" внутри каждой функции Javascript. Чтобы процитировать википедию:

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

Итак, поскольку вы можете определить переменные внутри функции, они "закрыты" для остальной части вашего кода, и поэтому я вижу это как закрытие. Таким образом, как я понимаю:

(function(){var a = 1;}())

Является (не очень полезным) примером закрытия. Или черт, даже просто:

function(){var a = 1;}

Но, я думаю, мое понимание может быть неправильным. Другие говорят мне, что для того, чтобы что-то было закрытием, оно должно оставаться государством, и так как ничто не остается выше этого кода, это не закрытие. Это говорит о том, что вам необходимо:

function(foo){foo.a = 1;}(bar); // bar.a = 1

или даже (для обеспечения немогитимости):

function(foo){var a = 1; bar.baz = function() { return a}}(bar); // bar.baz() = 1

Итак, технически говоря (я знаю, что некоторые из примеров практически бессмысленны, но), какие из приведенных выше примеров на самом деле являются примерами замыканий. И закрытие просто должно быть пространством (т.е. Внутри JS-функции), где переменные могут быть сохранены, которые не могут быть доступны извне или являются постоянством ключевой части определения закрытия?

ИЗМЕНИТЬ

Только что заметил определение вики для тега "закрытия" в Stack Overflow:

Закрытие - это функция первого класса, которая ссылается (закрывается) переменные из области, в которой она была определена. Если закрытие все еще существует после того, как его определяющая область действия заканчивается, переменные, которые она закрывает будет продолжать существовать.

В то время как SO wiki, конечно же, не является окончательным авторитетом, первое предложение, похоже, коррелирует с моим пониманием термина. Второе предложение затем предлагает, как можно использовать закрытие, но это не похоже на требование.

EDIT # 2

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

Ответ 1

Вас сбивают с толку неправильным предположением о том, откуда происходит слово "закрытие".

В теоретико-языковом контексте точкой замыкания является то, что функция может ссылаться на переменные, объявленные вне его собственного определения. Неважно, имеются ли внутренние переменные или внутренние переменные не видны снаружи. Другими словами, речь идет о том, чтобы увидеть функцию от ее среды определения, а не видеть ее вне функции.

Почему это странное слово? Посмотрите на функцию в последнем примере:

bar.baz = function() { return a }

Эта функция содержит упоминание переменной a, которая не определена в самом теле функции. Это "свободная" переменная тела функции, своего рода "дырка" в определении. Мы не можем выполнить функцию, не зная каким-то посторонним способом, к какой переменной относится идентификатор a в теле. Формирование замыкания на парах во время выполнения этого "открытого" тела функции со ссылкой на соответствующую переменную, тем самым закрывая отверстие в определении. И то, откуда происходит название.

(Если вы хотите полностью техническое объяснение, базовая концепция заключается в "закрытом" термине в лямбда-исчислении, что означает отсутствие свободных переменных. Только закрытый член имеет независимые значения. комбинация (обычно скомпилированной) незамкнутой части исходного кода вместе с контекстной информацией, которая позволяет ему вести себя так, как будто это был закрытый термин, и, следовательно, быть исполняемым).

Добавление: в общей идиоме

function() {
   var blah;
   // some code here
}();

точка не для того, чтобы получить замыкание (вы, конечно, получите ее, но она не делает ничего интересного для вас), но для создания локальной области для переменной blah. Локальная область зрения концептуально отличается от закрытия - на самом деле большинство C-lookalikes, кроме Javascript, создадут их в каждом блоке {}, тогда как они могут иметь или не иметь закрытий вообще.

Ответ 2

Ни один из ваших образцов не заканчивается технически. (Но четвертый образец может быть классифицирован как таковой в некоторых случаях, см. Ниже)

Закрытие - это структура данных, которая объединяет ссылку на функцию и непустой список кадров вызова (или областей), активных в момент объявления.

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

Например, в моем TIScript кадры вызова заменяются в стеке - когда вы выходите из функции, ее кадр вызова, который включает в себя набор переменных он использует очищается из стека. Создание закрытия в моем случае происходит, когда: VM встречает инструкцию объявления функции, и эта функция помечена (компилятором) как та, которая использует внешние переменные. В этом случае текущая цепочка кадров вызова, которая удерживает используемые переменные, перемещается из стека в кучу - преобразуется в объекты данных GCable и ссылается на эту функцию, и ее цепочка вызовов сохраняется как ссылка.

В вашем четвертом случае физически не требуется закрытие, которое нужно создать - нет необходимости хранить кадры вызовов для последующего использования - bar.baz содержит только число - не ссылку на функцию.

Но это:

function(foo){  
   var a = 1; 
   bar.baz = function() { return a; }; 
}

создает замыкание в поле bar.baz. При последующем вызове bar.baz() выполняется код функции, а значение переменной "a" будет взято из ссылки на внешний кадр вызова, который хранится в закрытии.

Надеюсь, что это что-то уберет для вас.

Ответ 3

Закрытие в JavaScript (и других языках) используется для управления и определения области. Нет требования, чтобы вы определяли функцию внутри функции, чтобы она "квалифицировалась" как закрытие. Тело функции - это закрытие. Одним из наиболее распространенных применений является объявление локальной переменной области видимости, которая становится частным или скрытым членом какого-либо другого объекта или функции, которые вы вернете, но это не является жестким правилом.