Введение
Закрытие - это функция, которая имеет разрешение на доступ к переменным в другой области функции.
Закрытие трудно понять в JavaScript. Многие передовые приложения полагаются на закрытие для их реализации. Давайте сначала рассмотрим пример ниже:
Функция Outter () {var i = 100; функция inner () {console.log (i); }}В приведенном выше коде, в соответствии с объемом переменной, все локальные переменные во внешней функции видны для внутренней функции; Локальные переменные во внутренних функции являются невидимыми вне функции внутренней, поэтому локальные переменные во внутренней функции не могут быть считываются вне функции.
Поскольку внутренняя функция может считывать локальные переменные внешней функции, при условии, что внутреннее значение используется в качестве возвращаемого значения, внутренние локальные переменные могут быть прочитаны непосредственно за пределами OUER.
Функция Outter () {var i = 100; функция inner () {console.log (i); } return inner;} var rs = over (); rs ();Эта функция имеет две характеристики:
После выполнения var rs = over () таким образом фактический RS указывает на функцию внутренней. Этот код на самом деле является закрытием. То есть, когда функция внутренней внутри внешней функции ссылается на переменную вне внешней функции, создается закрытие.
Объем
Проще говоря, Scope - это доступный диапазон переменных и функций, то есть область управления темой и жизненным циклом переменных и функций. В JavaScript объем переменных является глобальным и локальным.
Глобальный объем
var num1 = 1; function fun1 () {num2 = 2;}Вышеуказанные три объекта NUM1, NUM2 и FUN1 - все это глобальные области. Здесь следует отметить, что переменные, которые определяют прямые назначения в конце, автоматически объявляются как наличие глобальных областей;
Местный объем
function wroud () {var obj = "Я завернут оберткой, а внешняя часть обертывания не может получить непосредственно ко мне"; function innerfun () {// внешняя внешняя часть не может получить доступ ко мне}}Цепочка применения
Все в JavaScript является объектом. Эти объекты имеют свойство [[[Scope]], которое содержит набор объектов в области применения, созданной функцией. Эта коллекция называется цепочкой объема функции, которая определяет, какие данные могут быть доступны функцией.
Функция добавить (a, b) {return a+b;}При создании функции его свойство [[Scope]] автоматически добавит глобальную область
var sum = add (3,4);
Когда вызывается функция, создается внутренний объект, называемый контекстом выполнения. Этот объект Z определяет среду при выполнении функции. Он также имеет свою собственную цепочку областей для разрешения идентификатора, и его цепочка областей инициализируется как объект, содержащий в [[[Scope]] текущей функции, работающей.
Во время выполнения функции каждый раз, когда встречается переменная, будет проходить процесс анализа идентификатора, чтобы решить, где получить и хранить данные. Этот процесс начинается с головы цепочки применения, то есть ищет идентификатор одного и того же имени от активного объекта. Если это найдено, используйте переменную, соответствующую этому идентификатору. Если это не найдено, продолжайте искать следующий объект в цепочке областей, если все объекты ищут (последний - глобальный объект), не найден, идентификатор считается неопределенным.
Закрытие
Закрытие - это просто функция, которая обращается к его внешним переменным.
var quo = function (status) {return {getStatus: function () {return status; }}}Статус сохраняется в QUO, он возвращает объект, метод GetStatus в этом объекте относится к переменной состояния, то есть функция GetStatus обращается к своему внешнему состоянию переменной;
var newvalue = quo ('string'); // возвращать анонимный объект, на который ссылаются NewValue с newValue.getStatus (); // Доступ к статусу внутренней переменной QuoЕсли метод GetStatus недоступен, то статус будет автоматически переработан после Quo ('Sting'). Это именно потому, что возвращаемый анонимный объект ссылается глобальный объект, а анонимный объект зависит от статуса, поэтому он предотвратит выпуск статуса.
пример:
// схема ошибок var test = function (узлы) {var i; for (i = 0; i <nodes.length; i ++) {узлы [i] .onclick = function (e) {alert (i); }}}Анонимная функция создает закрытие, и I It Access Is Is I в внешней функции тестирования, поэтому каждый узел на самом деле относится к одному и тому же i.
// Улучшение решения VAR test = function (узлы) {var i; for (i = 0; i <nodes.length; i ++) {узлы [i] .onclick = function (i) {return function () {alert (i); }; }(я); }}Каждый узел связан с событием. Это событие получает параметр и сразу же работает, проходя в I. Поскольку это передается по значению, каждый цикл будет генерировать новую резервную копию для текущего i.
Роль закрытия
Функция Outter () {var i = 100; функция inner () {console.log (i ++); } return inner;} var rs = over (); rs (); // 100rs (); // 101rs (); // 102В приведенном выше коде RS является внутренней функцией закрытия. Всего RS работал три раза, первый раз составлял 100, второй раз составил 101, а третий раз составил 102. Это показывает, что локальная переменная I во внешней функции была сохранена в памяти и не была автоматически очищена при вызове.
Цель закрытия состоит в том, что после завершения и возврата внешнего исполнения, закрытие делает механизм сбора мусора JavaScript (сбор Grafge), а не перерабатывает память, занятую внешней, потому что выполнение внутренней функции внешнего зависит от переменных во внешней. (Другое объяснение: внешняя - родительская функция внутреннего, внутреннее присваивается глобальной переменной, в результате чего внутренний находится в памяти все время, а существование внутреннего зависит от внешней, потому что некоторые внешние всегда находятся в памяти и не будут собираться мусором и переработать после завершения вызова).
Закрытие имеет разрешение на доступ ко всем переменным внутри функции.
Когда функция возвращает закрытие, объем функции будет сохранена в памяти до тех пор, пока закрытие не будет.
Закрытие и переменные
Из -за механизма цепочки прицела закрытие может получить только последнее значение, содержащее любую переменную в функции. См. Следующий пример:
function f () {var rs = []; for (var i = 0; i <10; i ++) {rs [i] = function () {return i; }; } return rs;} var fn = f (); for (var i = 0; i <fn.length; i ++) {console.log ('function fn [' + i + '] () возвращаемое значение:' + fn [i] ());}Функции вернут массив. На первый взгляд, кажется, что каждая функция должна вернуть собственное значение индекса. Фактически, каждая функция возвращает 10. Это связано с тем, что цепочка применения первой функции содержит активные объекты функции F, и они относятся к одной и той же переменной i. Когда функция F возвращается, значение переменной I равно 10. В настоящее время каждая функция сохраняет один и тот же объект переменной переменной i. Мы можем заставить закрытие вести себя, как и ожидалось, создав другую анонимную функцию.
function f () {var rs = []; for (var i = 0; i <10; i ++) {rs [i] = function (num) {return function () {return num; }; }(я); } return rs;} var fn = f (); for (var i = 0; i <fn.length; i ++) {console.log ('function fn [' + i + '] () возвращаемое значение:' + fn [i] ());}В этой версии вместо того, чтобы напрямую назначать закрытие массиву, мы определяем анонимную функцию и назначаем результат немедленного выполнения анонимной функции на массив. Здесь анонимная функция имеет параметр num. При вызове каждой функции мы передаем переменную i. Поскольку параметры передаются по значению, переменная, которую я буду скопирована в параметр num. Внутри этой анонимной функции можно создать и возвращать закрытие NUM. Таким образом, каждая функция в массиве RS имеет копию собственной численной переменной, поэтому могут быть возвращены разные значения.
Этот объект в закрытии
var name = 'jack'; var o = {name: 'bingdian', getName: function () {return function () {return this.name; }; }} console.log (o.getName () () ()); // jackvar name = 'jack'; var o = {name: 'bingdian', getName: function () {var self = this; return function () {return self.name; }; }} console.log (o.getName () () ()); // БингдианУтечка памяти
function usdesshandler () {var el = document.getElementById ('demo'); el.onclick = function () {console.log (el.id); }} assignhandler ();Приведенный выше код создает закрытие в качестве обработчика событий EL Element, и это закрытие создает круговую ссылку. Пока анонимная функция существует, количество ссылок EL составляет не менее 1, потому что память, которую она занимает, никогда не будет переработана.
function usdesshandler () {var el = document.getElementById ('demo'); var id = el.id; el.onclick = function () {console.log (id); } el = null;} usdesshandler ();Установка переменной el null может определить объект DOM и гарантировать, что она обычно потребляет память.
Имитировать область на уровне блоков
Заявление, установленное в любой паре вьющихся скоб ({и}), принадлежит блоку, и все переменные, определенные в этом, невидимы за пределами блока кода, который мы называем областью на уровне блока.
(function () {// Область на уровне блока}) ();Применение закрытия
Защитите безопасность переменных в функции. Как и в предыдущем примере, только внутренняя функция может получить доступ к I во внешней функции, но не может быть доступна по другим каналам, тем самым защищая безопасность I.
Поддерживать переменную в памяти. Как и в предыдущем примере, из -за закрытия I в внешней функции всегда существует в памяти, поэтому каждый раз, когда rs () выполняется, я буду добавлять 1.