Прежде всего, вопреки тому, что большинство людей здесь говорят вам, замыкание - это , а не функция ! Так что же это это?
Это набор символов, определенных в «окружающем контексте» функции (известном как environment ), которые делают его выражением CLOSED (то есть выражением, в котором каждый символ определен и имеет значение, поэтому его можно оценить).
Например, если у вас есть функция JavaScript:
function closed(x) {
return x + 3;
}
это закрытое выражение , потому что в нем определены все символы, встречающиеся в нем (их значения понятны), так что вы можете оценить его. Другими словами, это автономный .
Но если у вас есть такая функция:
function open(x) {
return x*y + 3;
}
это открытое выражение , потому что в нем есть символы, которые не были определены в нем. А именно y
. Когда мы смотрим на эту функцию, мы не можем сказать, что такое y
и что это значит, мы не знаем ее значения, поэтому мы не можем оценить это выражение. То есть мы не можем вызвать эту функцию, пока не скажем, что y
должно означать в ней. Эта y
называется свободной переменной .
Это y
просит об определении, но это определение не является частью функции - оно определяется где-то еще, в его «окружающем контексте» (также известном как среда ). По крайней мере, это то, на что мы надеемся: P
Например, это можно определить глобально:
var y = 7;
function open(x) {
return x*y + 3;
}
Или это может быть определено в функции, которая оборачивает его:
var global = 2;
function wrapper(y) {
var w = "unused";
return function(x) {
return x*y + 3;
}
}
Часть среды, которая дает свободным переменным в выражении их значения, является замыканием . Это называется так, потому что оно превращает выражение open в closed , предоставляя эти отсутствующие определения для всех его свободных переменных , так что мы мог оценить это.
В приведенном выше примере внутренняя функция (которой мы не дали имя, потому что оно нам не нужно) является открытым выражением , потому что переменная y
в ней равна free - его определение находится за пределами функции, в функции, которая ее оборачивает. среда для этой анонимной функции представляет собой набор переменных:
{
global: 2,
w: "unused",
y: [whatever has been passed to that wrapper function as its parameter `y`]
}
Теперь замыкание - это та часть этой среды, которая закрывает внутреннюю функцию, предоставляя определения для всех ее свободных переменных . В нашем случае единственной свободной переменной во внутренней функции была y
, поэтому закрытие этой функции - это подмножество ее окружения:
{
y: [whatever has been passed to that wrapper function as its parameter `y`]
}
Два других символа, определенных в среде, являются , а не частью замыкания этой функции, поскольку она не требует их запуска. Они не нужны для закрытия этого.
Подробнее о теории здесь:
https://stackoverflow.com/a/36878651/434562
Стоит отметить, что в приведенном выше примере функция-обертка возвращает свою внутреннюю функцию в качестве значения. Момент, когда мы вызываем эту функцию, может быть удален во времени с момента, когда функция была определена (или создана). В частности, его функция обертывания больше не работает, а его параметры, которые были в стеке вызовов, больше не присутствуют: P Это создает проблему, потому что внутренней функции требуется y
, чтобы быть там при вызове! Другими словами, он требует, чтобы переменные были закрыты, чтобы как-то пережить функцию-обертку и быть там, когда это необходимо. Поэтому внутренняя функция должна сделать снимок этих переменных, которые закрывают их и хранят где-нибудь в безопасном месте для дальнейшего использования. (Где-то за пределами стека вызовов.)
И именно поэтому люди часто путают термин замыкание с тем, что это особый тип функции, который может делать такие снимки внешних переменных, которые они используют, или структуры данных, используемой для хранения этих переменных для дальнейшего использования. Но я надеюсь, что теперь вы понимаете, что они не сами замыкания - это всего лишь способы реализации замыканий в языке программирования или языковых механизмов, которые позволяют переменным из замыкания функции быть там, когда это необходимо. Есть много заблуждений относительно замыканий, которые (излишне) делают эту тему намного более запутанной и сложной, чем она есть на самом деле.