Закрытие, это действительно красиво

внешний интерфейс GitHub JavaScript Chrome
Закрытие, это действительно красиво

ОТ Чжан Цзяньчэн (prettyEcho@github)

Если не указано иное, все материалы на этой странице защищены авторством Creative Commons (CC BY 2.5 AU) совместное использование протокола

🐬 🐬 Комментарии и звезды приветствуются 🐳 🐳

Я очень нервничал, когда писал эту статью 💢, потому что для нашего сегодняшнего главного героя:Закрытие, Многие друзья написали статьи об этом, и я думаю, вы их много читали. В этих статьях четко объяснялся этот подобный миф в JS? Честно говоря, есть, но их немного.

Первоначальный замысел написания этой статьи:Пусть все друзья, прочитавшие эту статью, досконально разберутся в замыканиях => повысят уровень JS => смогут писать более качественный JS-код.

Причина, по которой Кайвен сказала, что у меня тревожное настроение, заключается в том, что я боюсь, что не достигну первоначального замысла написания этой статьи, но я уверен, что я также буду усердно работать для достижения своей цели. Если в тексте есть какое-либо вводящее в заблуждение утверждение, каждый может меня исправить, и я очень благодарен. 🙏 🙏 🙏

Давайте начнем:

Я полагаю, что многие любители JS слышали об этом предложении:Замыкания важны, но их трудно понять.

Сначала я чувствовал то же самое, но когда я попытался изучить некоторые глубокие принципы JS, я почувствовал, что замыкания не так уж сложны для понимания, но вызывают у меня прекрасное чувство. Когда я полностью понял закрытие, у меня на сердце появилось очень приятное чувство, прямо как от красоты «вино еще выпито, цветы еще не распустились».

Приоткройте завесу тайны закрытия

Сначала рассмотрим пример замыкания:

function foo() {
    let a = 2;

    function bar() {
        console.log( a );
    }

    return bar;
}

let baz = foo();

baz();

Все, должно быть, написали подобный код.Я полагаю, что многие мелкие партнеры также знают, что этот код применяет замыкание, но почему замыкание генерируется и где замыкание?

Приходите, давайте анализировать медленно:

Прежде всего, вы должны знать, что такое замыкание, прежде чем сможете проанализировать, почему замыкание генерируется и где оно находится?

Когда функция может запомнить и получить доступ к лексической области видимости и цепочке областей видимости, в которых она расположена, особенно к доступу за пределами ее определенной области, функция и ее верхний контекст выполнения вместе составляют замыкание.

Несколько моментов для ясности:

  1. Замыкание должно быть функциональным объектом (Исследования по закрытию Wintercn)
  2. Замыкания тесно связаны с лексической областью видимости, цепочкой областей действия и механизмами сборки мусора.
  3. Закрытие генерируется только тогда, когда функция должна быть доступна за пределами области ее определения.
  4. Закрытие состоит из функции и ее верхнего контекста выполнения (я объясню это немного подробнее)

Что такое замыкание, мы разобрались, давайте посмотрим, как генерируется замыкание.

Далее, я предполагаю, что вы прочитали две мои предыдущие статьиВот как JavaScript работает внутриа такжеТщательно понимать область действия JavaScript, Рекомендуется сначала прочитать и понять механизм и область выполнения JS, а также другие связанные знания, а затем понять закрытие, иначе понимание может быть неполным.

Теперь я предполагаю, что движок JS выполняет эту строку кода

let bar = foo();

На данный момент область видимости JS выглядит так:

closure

В это время функция foo была выполнена, и механизм сборки мусора JS должен автоматически пометить ее как «уходящую из среды», ожидая следующего выполнения механизма рециркуляции, чтобы освободить свою память (отметить очистку).

но,Давайте внимательно посмотрим на розовую стрелку на рисунке Мы указываем ссылку bar на baz Именно такое присваивание ссылки не позволяет механизму сборки мусора перерабатывать foo, в результате чего вся цепочка областей действия bar сохраняется..

Следующий,baz()Execute, bar попадает в стек выполнения, и формируется замыкание (foo), переменная a в пузырьке ее родительской области все еще может быть доступна в bar в это время.

Это может быть не очень понятно.Далее давайте посмотрим на процесс генерации замыкания с помощью инструментов отладки Chrome.

Когда движок JS выполняет эту строку кодаlet bar = foo();Время:

closure

Как показано на рисунке,let baz = foo();Завершено, готовится к выполнениюbaz();, в настоящее время в стеке вызовов есть только глобальный контекст.

следующийbaz();воплощать в жизнь:

closure

Мы видим, что в этот момент bar входит в стек вызовов и формируется Closure(foo).

Вот пункты, о которых я упоминал выше:

  1. Второй пункт выше (замыкания тесно связаны с лексической областью видимости, цепочкой областей видимости и механизмом сборки мусора) должен быть понятен всем.
  2. Третий пункт выше, когда функция baz выполняется, замыкание генерируется
  3. Четвертый пункт выше, замыкание — это foo, а не bar.Многие книги («вы не знаете JavaScript», «Расширенное программирование на JavaScript») подчеркивают сохраненные ссылки, то есть бар в приведенном выше примере — это замыкание, а Chrome думает что сохраненное закрытое пространство foo является закрытием. Я согласен с суждением Chrome по этому вопросу (только мое собственное понимание. Если у вас разные мнения, добро пожаловать на обсуждение)

Артистизм закрытия

Я считаю, что самые прекрасные вещи в мире часто находятся вокруг нас, обычно это не так таинственно, так незаметно, но нам не хватает пары глаз, чтобы обнаружить красоту.

В жизни мы тратим время на то, чтобы замедлиться и насладиться каждой минутой и секундой нашей жизни, и мы пожинаем еще один слой удовольствия, который дает нам жизнь.

То же самое относится и к замыканиям.Это не очень таинственно, но можно увидеть повсюду в наших программах.Когда мы успокаиваемся и пробуем вкус замыканий, мы обнаруживаем, что они источают некую художественную красоту, простую, нежную и элегантную.

closure

Если подумать, в нашей модели пузырьков с областью видимости цепочки областей видимости позволяют нашему внутреннему пузырю полос «видеть» внешний мир, а замыкания позволяют нашей внешней области видимости «сосредоточиться» на том, что происходит внутри. Видишь ли, если мы захотим,Внутренний мир и внешний мир связаны.

Примечания по применению затворов

Замыкание — определенно благородное существование в JS, оно делает возможным множество невозможных кодов, но, хотя оно и хорошо, его нужно использовать разумно, иначе оно не только не даст желаемого эффекта, но иногда может иметь неприятные последствия.

  • Утечка памяти

    Объем доступной памяти, который JavaScript выделяет веб-браузерам, обычно меньше, чем объем, выделяемый настольным приложениям, главным образом для того, чтобы веб-страницы JavaScript не исчерпывали всю системную память и не приводили к сбою системы.

    Следовательно, чтобы повысить производительность страницы, мы должны убедиться, что страница занимает наименьшее количество ресурсов памяти, то есть мы должны убедиться, что исполняемый код сохраняет только полезные данные, и как только данные больше не нужны, мы должны позволить механизму сборки мусора переработать его, освободив память.

    Мы все уже знаем, что замыкания не позволяют механизму сборки мусора освобождать переменные, поэтому переменные всегда будут существовать в памяти, даже когда переменные больше не используются, это вызовет утечки памяти, что серьезно повлияет на производительность страницы. Поэтому, когда переменный объект больше не доступен, мы освобождаем его.

    Возьмем приведенный выше код в качестве примера:

     function foo() {
         let a = 2;
     
         function bar() {
             console.log( a );
         }
     
         return bar;
     }
     
     let baz = foo();
     
     baz(); //baz指向的对象会永远存在堆内存中
     
     baz = null; //如果baz不再使用,将其指向的对象释放
     
    

    Что касается утечек памяти, рекомендуетсяБлог учителя Жуань Ифэн.

Применение затворов

  1. модуль

    Модуль должен иметь частные свойства, частные методы и общедоступные свойства и общедоступные методы.

    Замыкания могут раскрывать общедоступные свойства и методы модулей.

    var myModule = (function (window, undefined) {
    	let name = "echo";
    	
    	function getName() {
    		return name;
    	}
    	
    	return {
    		name,
    		getName
    	}
    })(window);
    
    console.log( myModule.name ); // echo
    console.log( myModule.getName() ); // echo
    

    Ключевое слово «return» назначает экспорт ссылки на объект в myModule, который применяется к замыканию.

  2. Задержка (setTimeout), Счетчик (setInterval)

    Вот простая запись распространенного вопроса интервью о замыканиях.

    for( var i = 0; i < 5; i++ ) {
    	setTimeout(() => {
    		console.log( i );
    	}, 1000 * i)
    }
    

    Все знают ответ:Выводить 5 каждую секунду, всего 5 раз.

    Итак, как это сделатьВыводить число каждую секунду, использовать его как 0, 1, 2, 3, 4Шерстяная ткань?

    Мы вводим здесь только решение замыканий, другие решения, такие как область видимости блока и т. д., мы не будем их здесь обсуждать.

    for( var i = 0; i < 5; i++ ) {
    	((j) => {
    		setTimeout(() => {
    			console.log( j );
    		}, 1000 * j)
    	})(i)	
    }
    

    Метод setTimeout использует замыкание, которое внутренне запоминает лексическую область видимости и цепочку областей видимости, в которой находится каждый цикл.

    Поскольку функция обратного вызова в setTimeout будет выполняться в конце текущей очереди задач, значение i, запоминаемое функцией обратного вызова setTimeout в каждом цикле в первом примере выше, является значением в области действия цикла for.5, и число i, запомненное во втором примере, — это значение j в самовыполняющейся функции родительской области setTimeout, которая в свою очередь равна 0, 1, 2, 3, 4.

  3. слушатель

    var oDiv = document.querySeletor("#div");
    
    oDiv.onclick = function() {
    	console.log( oDiv.id );
    }
    

=- Что касается замыканий, кажется, я ясно дал понять, вы это ясно видели? Дайте мне знать -=

🤗 Если вы считаете, что текст неплох, подписывайтесь на меняgithubЧто ж, давайте расти вместе. . .