Пополнить:
Закрытие - это сложность на языке JavaScript и его функции. Многие передовые приложения полагаются на закрытие для реализации.
Особенности закрытия
Закрытие имеет три характеристики:
1. Функция вложенных функций
2. Функция может относиться к внешним параметрам и переменным внутри
3. Параметры и переменные не будут собираться механизмом сбора мусора
Определение закрытия и его преимуществ и недостатков
Закрытие относятся к функциям, которые имеют доступ к переменным в области другой функции. Наиболее распространенным способом создания закрытия является создание другой функции в одной функции и получить доступ к локальным переменным этой функции через другую функцию.
Недостатком закрытия является то, что они являются резидентами, которая увеличит использование памяти, и ненадлежащее использование может легко привести к утечке памяти.
Закрытие является основной особенностью языка JavaScript. Основное применение закрытия в основном предназначено для: проектирование частных методов и переменных.
После выполнения общей функции локальный активный объект разрушается, и только глобальная область сохраняется в памяти. Но ситуация закрытия отличается!
Поговорить о теме
1. Определение закрытия?
Давайте посмотрим на некоторые определения о закрытии:
1. Закрытие относится к функции, которая имеет разрешение на доступ к переменным в другой области функции.
2. Функциональные объекты могут быть связаны с помощью цепочек объема, и переменные внутри корпуса функции могут быть сохранены в области функции. Эта характеристика называется «закрытие».
3. Внутренние функции могут получить доступ к параметрам и переменным внешним функциям, которые определяют их (кроме этого и аргументы).
Если вы хотите систематически изучить концепцию закрытия JS, вы можете обратиться к колонке электронной книги JS E-Book на веб-сайте wulin.com, чтобы узнать.
Давайте суммируем определение
1. Вы можете получить доступ к функциям переменных в области внешней функции
2. Переменные внешних функций, доступных внутренними функциями, могут быть сохранены в рамках внешней функции без переработки-это ядро. Позже, когда мы сталкиваемся с закрытием, мы должны подумать об этом. Мы должны сосредоточиться на переменной, на которую ссылается закрытие.
Создать простое закрытие
var waysname = function () {var name = 'jozo'; return function () {alert (name);}}; var showers = sayname (); сказать();Давайте интерпретируем следующие два предложения:
• var говорит = sayname (): возвращает анонимную внутреннюю функцию, хранящуюся в переменной, и относится к имени переменной внешней функции. Из -за механизма сбора мусора, после выполнения функции SayName, имя переменной не разрушено.
• SAID (): выполнить возвращенную внутреннюю функцию и все еще получить доступ к имени переменной и вывода 'Jozo'.
2. Цепочка применения в закрытии
Понимание цепочек областей также полезно для понимания закрытия.
Методы поиска переменных в объеме должны быть очень знакомыми, но на самом деле это то, что ищет вверх по цепочке областей.
Когда функция называется:
1. Сначала создайте контекст выполнения и соответствующую цепочку областей;
2. Добавьте аргументы и другие значения именованных параметров в активный объект функции (объект активации)
Цепочка применения: активный объект текущей функции имеет наивысший приоритет, за которым следует активное объект внешней функции, а активный объект внешней функции внешней функции уменьшается в последовательности до конца цепочки объема - глобальная область. Приоритетом является порядок поисков переменных;
Давайте сначала посмотрим на нормальную цепочку сцепления:
Функция ShowerName (имя) {return name;} var showers = sayname ('jozo');Этот код содержит две области: a. глобальный объем; B.SayName Функция, то есть есть только два переменных объекта. При выполнении в соответствующую среду выполнения, объект переменной станет активным объектом и будет подтолкнут к переднему концу цепочки объема среды выполнения, то есть он становится самым высоким приоритетом. Поговорите с картинкой:
Эта картина также доступна в JS Advanced Programming Books, и я все это зарисовал.
При создании функции SAYNAME () создается цепочка областей, содержащую объект переменной, то есть цепь областей, индексируемая по 1 на рисунке, и сохраняется во внутреннем атрибуте [[Scope]]. Когда вызывается функция sayname (), создается среда выполнения, а затем цепочка областей строится путем копирования объекта в атрибуте [[[Scope]] функции. После этого создается еще один активный объект (индексируемый 0 на рисунке) создается и выдвигается в переднюю часть цепочки объема среды выполнения.
Вообще говоря, когда функция выполняется, локальный активный объект будет уничтожен, и только глобальный объем сохраняется в памяти. Однако ситуация закрытия отличается:
Давайте посмотрим на цепочку закрытия прицела:
Функция showername (name) {return function () {return name;}} var ways = sayname ('jozo');Этот экземпляр закрытия имеет еще один объем для анонимной функции, чем в предыдущем примере:
После того, как анонимная функция возвращается из функции sayname (), ее цепочка областей инициализируется к активному объекту, а объект глобальной переменной, содержащий функцию sayname (). Таким образом, анонимная функция может получить доступ ко всем переменным и параметрам, определенным в sayname (). Что еще более важно, после выполнения функции sayname () ее активный объект не будет разрушен, поскольку цепочка областей анонимной функции все еще относится к активному объекту. Другими словами, после выполнения функции sayname () цепочка областей ее среды выполнения будет уничтожена, но ее активный объект будет оставаться в памяти, зная, что анонимная функция будет уничтожена. Это также проблема утечки памяти, которая будет обсуждаться позже.
Я не пишу так много о проблемах цепочки сфера, и писать вещи в книге также очень утомительно o (□) o
3. Пример закрытия
Пример 1: реализация накопления
// Метод 1var a = 0; var add = function () {a ++; console.log (a)} add (); add (); // Метод 2: закрытие var add = (function () {var a = 0; return function () {a ++; console.log (a);}}) (); console.log (a ++; console.log (a);}}) (); console.log (a); // undfinedAdd (); add ();Для сравнения, метод 2 более элегантен, а также уменьшает глобальные переменные и приватизирует переменные.
Пример 2: Добавьте событие Click в каждый LI
var oli = document.getElementsbytagname ('li'); var i; for (i = 0; i <5; i ++) {oli [i] .onclick = function () {alert (i);}} console.log (i); // 5 // Выполнить анонимную функцию (function () {alert (i); // 5} ());Приведенное выше классический пример. Мы все знаем, что результат выполнения состоит в том, что 5 всплывают, и мы также знаем, что закрытия могут быть использованы для решения этой проблемы, но вначале я все еще не могу понять, почему 5 появляются и почему закрытия могут решить эту проблему. Позже я разобрался и дал понять:
а Давайте сначала проанализируем ситуацию до использования закрытия: в цикле для цикла мы связываем анонимную функцию с каждому событию Li Click, и значение переменной I возвращает в анонимной функции. Когда цикл заканчивается, значение переменной, которую я становится 5. В настоящее время мы нажимаем на каждый LI, то есть выполняем соответствующую анонимную функцию (см. Код выше). Это переменная, которую я уже 5, поэтому каждый щелчок появляется 5. Поскольку каждая анонимная функция, возвращаемая здесь, относится к одной и той же переменной I, если мы создадим новую переменную для сохранения текущего значения I при выполнении цикла, а затем позвольте анонимной функции применить эту переменную и, наконец, вернуть эту анонимную функцию, чтобы наша цель была достигнута. Это достигается с использованием закрытия!
беременный Давайте проанализируем ситуацию при использовании закрытия:
var oli = document.getElementsbytagname ('li'); var i; for (i = 0; i <5; i ++) {oli [i] .onclick = (function (num) {var a = num; //, чтобы проиллюстрировать проблему возврата функции () {alert (a);}}) (i)} console.log (i); // 5Когда цикл для выполнения, анонимная функция, связанная с событием Click, передается I и немедленно выполнена для возврата внутренней анонимной функции. Поскольку параметры передаются значением, формальный параметр NUM сохраняет текущее значение I, а затем присваивает значение локальной переменной a. Затем внутренняя анонимная функция сохраняет ссылку на A, то есть сохраняет текущее значение i. Таким образом, после выполнения цикла нажмите на каждый LI, и возвращаемая анонимная функция появит значение сохраненного a.
4. Применение закрытия
Давайте посмотрим на цель закрытия. На самом деле, используя закрытие, мы можем сделать много вещей. Например, моделируйте объектно-ориентированный стиль кода; Экспресс код более элегантно и кратко; и повысить эффективность выполнения кода в некоторых аспектах.
1. Анонимная функция самостоятельного выполнения
В реальных ситуациях мы часто сталкиваемся с ситуацией, когда некоторые функции должны выполняться только один раз, а их внутренние переменные не нужно поддерживать, например, инициализация пользовательского интерфейса, поэтому мы можем использовать закрытие:
// Измените все лирифы на Red (function () {var els = document.getElementsbytagname ('li'); for (var i = 0, lng = els.length; i <lng; i ++) {els [i] .style.color = 'red';}}}) (););Мы создаем анонимную функцию и немедленно выполняем ее. Поскольку внешний не может ссылаться на переменные внутри него, локальные переменные, такие как ELS, I и LNG, будут выпущены вскоре после выполнения, сохраняя память!
Ключ в том, что этот механизм не загрязнет глобальный объект.
2. Реапенцирование инкапсуляции/модульный код
var person = function () {// Область переменной находится внутри функции, а var name = "default" не может быть доступен снаружи. return {getName: function () {return name; }, setName: function (newName) {name = newName; }}} (); console.log (person.name); // прямой доступ, результатом является неопределенная console.log (person.getName ()); // default person.setname ("jozo"); console.log (person.getName ()); // Джозо3. Реализовать объектно-ориентированные
Таким образом, разные объекты (экземпляры классов) имеют независимые члены и государства и не мешают друг другу. Хотя нет такого механизма, как класс в JavaScript, используя закрытие, мы можем имитировать такие механизмы. Давайте поговорим о приведенном выше примере:
function person () {var name = "default"; return {getName: function () {return name; }, setName: function (newName) {name = newName; }}}; var person1 = person (); print (person1.getName ()); john.setname ("person1"); print (person1.getName ()); // person1 var person2 = person (); print (person2.getName ()); jack.setname ("erson2"); print (erson2.getName ()); // person2Два экземпляра человека 1 и Person2 не мешают друг другу! Потому что эти два случая имеют независимый доступ к имени участника.
5. Утечки и решения памяти
Механизм утилизации мусора
Говоря об управлении памятью, он, естественно, неотделим от механизма сбора мусора в JS. Есть две стратегии для реализации сбора мусора: отметка и подсчет ссылок ;
Удаление отметка: когда запускается сборщик мусора, он будет отмечать все переменные, хранящиеся в памяти. Затем он удалит теги переменных в среде и теги переменных, на которые ссылаются переменные в окружающей среде. После этого, если переменная снова помечена, это означает, что переменная готова к удалению. До 2008 года IE, Firefox, Opera, Chrome и Javari's JavaScript использовали этот метод;
Ссылка: отслеживает количество раз, когда ссылается на каждое значение. Когда будет объявлена переменная, и значение ссылочного типа назначается переменной, количество раз, когда это значение упоминается, составляет 1. Если это значение присваивается другой переменной, количество раз, когда ссылка увеличивается на 1. Наоборот, если переменная отклоняется от ссылки на значения, количество ссылок на значение уменьшается на 1, а когда число времени будет дождаться, чтобы получить набор для повторного цикла.
Большая проблема с этим методом заключается в круговой ссылке, то есть объект A содержит указатель на B, а объект B также содержит ссылку на A. Это может привести к переработке большого количества памяти (утечки памяти), потому что их ссылки никогда не могут быть 0. В ранних версиях IE (IE4-IE6) механизм сбора мусора. Одной из причин, по которой закрытие вызвало утечку памяти, был недостаток этого алгоритма.
Мы знаем, что некоторые объекты в IE не являются местными объектами JavaScript. Например, объекты в BOM и DOM реализованы в форме COM -объектов, а механизм сбора мусора объектов COM принимает отсчет справочника. Поэтому, хотя двигатель JavaScript IE принимает стратегию очистки тегов, доступ к COM -объектам по -прежнему основан на подсчете ссылок, поэтому, если объекты COM будут разработаны в IE, возникнет проблема круговых ссылок!
Возьмите каштан:
window.onload = function () {var el = document.getElementbyid ("id"); el.onclick = function () {alert (el.id);}}Почему этот код вызывает утечки памяти?
el.onclick = function () {alert (el.id);};При выполнении этого кода объект анонимной функции назначается атрибуту Onclick EL; Затем анонимная функция относится к объекту EL внутри, и есть круговая ссылка, поэтому ее нельзя переработать;
Решение:
window.onload = function () {var el = document.getElementbyId ("id"); var id = el.id; // unreference el.onclick = function () {alert (id); } el = null; // Очистить активный объект во внешней функции, на который ссылаются закрытие}Выше приведено краткое изложение соответствующих знаний о утечке памяти сбора мусора JS Cope Cope Collection, представленной вам редактором. Я надеюсь, что это будет полезно для всех!