Итак, вернёмся с
того блога к этому вопросу.
Если попробовать описать ещё более обще, и, в альтернативу "замыкание - функция", поставить "функцию" в пассивный залог (как объект замыкания), то также можно сказать, что
замыкание - это
эффект, при котором:
а) область видимости (scope) контекста,
породившего блок кода, а также,
все вышестоящие области видимости, доступны этому порождённому блоку кода;
б) порождённый блок кода может "пережить" порождающий его контекст.
--- Специально не написал в общем определении - "функция", т.к. в Ruby, например, замыкание - это либо блок (block), либо lambda, либо Proc, но касательно JavaScript, будем говорить "функция". Также, упростив, будем говорить, что
замыкание - это функция, а не эффект (к тому же, на основную суть это не влияет). ---
Обязательно ли наличие сразу двух пунктов, чтобы назвать функцию замыканием?
Теоретически и практически, пункт а) реализуется обычной функцией в глобальном скопе:
var a = 10;
function x() {
alert(a);
}
x(); // 10
Что произошло:
- глобальный контекст породил функцию "x";
- функция "x" получила ссылку на scope глобального контекста (это её
[[scope]]; подробней можно почитать в стандарте и статьях, либо здесь можно будет рассказать, если потребуется);
- при активации функции создалась цепь скопов (scope chain, Scope, - с большой буквы обозначается):
Scope = [[scope]] + текущий Variable Object (VO) функции (в новых редакциях - Environment Object, EO), в которой будут искаться переменные, используемые в функции;
- переменная "а" не определена в VO(x), т.е. является
свободной для функции "x" и будет найдена в скопе window;
Таким образом, первое условие, если рассматривать
общий механизм (поиск переменных в scope chain), реализуемо на
любых функциях (не важно - анонимных или нет, вложенных или глобальных). Это к теории, что все функции - замыкания (когда основным моментом считается наличие свободных переменных). Если же конкретизировать, здесь можно разделять (как это сделано в Википедии) лексические и глобальные переменные. Однако, мне это разделение кажется условным, поскольку, повторю,
механизм цепи скопов - одинаков.
Однако, если пойти дальше, и, всё-таки, попытаться разделять функции на "замыкания" и "не-замыкания", то нужно рассмотреть пункт б). Обратимся к нему.
Глобальная функция не может "переживать" свой контекст, т.к. глобальный контекст никуда не "умирает"; он существует на протяжении жизни запущенной программы. В свою очередь
вложенная функция такую возможность имеет:
var a = 10;
function y() {
return function z() {
alert(a);
};
}
dz = y();
dz(); // 10
Снова видно, что функция "z" имеет на борту свободную переменную "а", однако, эта переменная не определена в породившем функцию "z" скопе (контекст функции "y"), но определена в скопе выше. Плюс ко всему - функция пережила породивший её контекст.
Кстати, если бы мы не написали alert(a) (фактически нет свободных переменных), то это не значит, что функция "z" не имеет доступ как к скопу "y", так и к вышестоящему (глобальному) скопу. Этот [[scope]], как было сказано выше, попадает в функцию "z" при её создании.
Стало быть, теоретически достаточно этого пунка б), чтобы сделать разделение на "замыкания" и "не-замыкания". Теоретически, - т.к. пункт а) (свободные переменные) выполняется неявно - из глобального контекста.
Но, всё же, с прикладной точки зрения, этот механизм удобен, когда пункт а), наряду с
обязательным пунктом б) (в теории разделения на "замыкания" и "не-замыкания") является явным, т.е. свободные переменные объявлены в скопах ниже глобального, но выше родного VO (EO) функции.
Поэтому, подытожив, можно остановится на твоём описании,
Zeroglif, как более полном: есть теория, что все функции - замыкания (однако, здесь - только теоретический интерес), но с практической точки зрения - должны выполняться "по-полной" оба пункта второй теории (с разделением на "замыкания" и "не-замыкания").
update:
А, да. И о терминах: "двойное", "тройное", "десятикратное" замыкание. Естественно, термины прикладные (не академические), т.к. более относятся к уровню вложенности scope chain и не являются основной характеристикой замыканий. Хотя, для удобства можно и так, наверное, говорить. Но только не в ключе - "какая интересная и "страшная" вещь - двойное замыкание".
update2:
Сообщение от Zeroglif
|
Только определение, обобщающее суть, без примеров, без воды
|
А, пардон, не обратил особого внимания на эту просьбу, подробно расписал. Ок. Только суть: можно выделить две теории: 1) все функции замыкания (т.к. ... здесь можно привести пару примеров), но (вторая теория) практическую ценность составляет наличие двух пунктов - а) функция переживает свой лексический контекст, б) имеются свободные переменные.