Короткая и простая тема. Думал я поначалу. Есть, как минимум, два объяснения, что это такое.
Во-первых, замыкания - это, грубо говоря, способ создать приватное свойство. То есть есть свойство объявляется внутри функции, а сама функция его возвращает с помощию внутренней функции. Это означает, что свойство остается неизменным, кто бы ни вызывал функцию, потому что область его видимости остается внутри. Например, функция:
function private() {
let a = 0;
return function() {
return a;
};
};
В ней никто не имеет доступа к переменной а извне, и потому не может её изменить.
Во-вторых, замыкания - это функция внутри функции. Основная польза от этого в том, что её можно присвоить какой-то переменной, а вызвать потом через эту переменную. Например, результатом присвоения
let variable = private();
будет variable, которая при вызове variable() будет возвращать а.
Одним из самых распространенных применеий замыканий является счетчик:
function private() {
let a = 0;
return function() {
return a++;
}
}
let counter = private();
тогда при каждом вызове counter() будет возвращаться значение, на единицу большее, чем при предыдущем вызове функции.
Вот тут-то мне и стало непонятно: если функция отработала, то она должна была бы уничтожиться? Тогда в следующий раз заново бы создавалась и инициализировалась новая let a = 0;? Тогда о каком счетчике может быть речь?
Ответ пришлось поискать, и вот он: объект существует пока существует ссылка на него. И здесь мы имеем, что да, функция private() отработала, но внутренняя по отношению к ней функция продолжает существовать, поскольку в момент вызова private() её присвоили другому объекту (где она может ожидать своего вызова). А значит, и private() не уничтожена, а переменная изменила своё значение (в данном случае а = а+1)!
Если детализировать, то:
1. При вызове функции создается лексическое окружение (этой функции) - LexicalEnvironment, в котором, например, будут искаться переменные, если они не были найдены локально внутри. Грубо говоря, это внешняя область видимости по отношению к данной функции.
2. Также создании любая функции получает скрытое свойство [[Environment]], которое ссылается на её окружение (и тем самым как бы "запоминает" его). Для внутренней функции окружением будет внешняя функция с теми значениями переменных, которые на данный момент в ней есть.
То есть в момент вызова counter() значение переменной а будет находится во внешней по отношению к ней private(), и равняться это значение будет тому, которое существует на момент очередного вызова counter(). Другими словами, каждый новый counter() будет находить новую переменную а в своем окружении (имеющую то значение, которое осталось в результате предыдущего вызова counter()). Вот вам и счетчик.
Подробнее - здесь.
Комментариев нет:
Отправить комментарий