Поговорим о закрытиях

JavaScript
Поговорим о закрытиях

предисловие

Когда замыкания создаются и когда уничтожаются? Какая конкретная реализация?

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

🤭Чтобы лучше понять замыкания, необходимо сначала понять содержание, связанное с областью действия и контекстом выполнения:

Контекст выполнения JavaScript — стек выполнения

Динамическая область видимости Javascript, о которой вы не знали

Говорить особо нечего, это просто вопрос для размышления 🤔

		var name = "The Window";
        var object = {
            name: "My Object",
            getNameFunc: function () {
                return function () {
                    return this.name;
                };
            }
        };
        alert(object.getNameFunc()());

👆 Конечно, у js есть прочная основа, вы должны разбираться в деталях внутри, прочитав содержание, вы сможете легко решить эту проблему✊

Нажмите здесь, чтобы увидеть
 
     obj.getNameFunc()()实际上是在全局作用域中调用了匿名函数,this指向了window。这里要理解*函数名与函数功能(或者称函数值)是分割开的,不要认为函数在哪里,其内部的this就指向哪里。匿名函数的执行环境具有全局性,因此其 this 对象通常指向 window
  

что такое закрытие

Посмотрим, что скажет Руби👇

闭包是指有权访问另外一个函数作用域中的变量的函数

Давайте сначала посмотрим на определение MDN 👇

函数和对其周围状态(**lexical environment,词法环境**)的引用捆绑在一起构成**闭包**(**closure**)。也就是说,闭包可以让你从内部函数访问外部函数作用域。在 JavaScript 中,每当函数被创建,就会在函数生成时生成闭包。

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

网上对于闭包的定义各种各样,每个人对闭包的理解不同,自然定义就不同,那么我也不去定义闭包,自己意会吧👊

Если вам нужно понять, есть два понимания:

1️⃣ Замыкания — это вложенные внутренние функции (большинство людей)

2️⃣ Объекты, содержащие ссылочные переменные (или функции) (очень мало)

Я думаю, что замыкания существуют во вложенных внутренних функциях 😊

Пишем демо для второго понимания👇

function count () {
            var x = 0
            return {
                add() {
                    x++;
                },
                print() {
                    console.log(x)
                }
            }
        }
        let demo = count();
        demo.add()
        demo.print()
        demo.add()
        demo.print()

Хм 🙃 Это можно только понять и не описать словами, давайте посмотрим ниже!

Жизненный цикл закрытия

Причина закрытия

Прежде всего, мы должны понять концепцию цепочки областей видимости, которая на самом деле очень проста — в ES5 всего две области видимости.

1️⃣Глобальный охват 2️⃣ Локальный охват

При обращении к переменнойИнтерпретатор сначала будет искать идентификатор в текущей области видимости, а если не найдет, то будет искать его в родительской области, пока не найдет идентификатор переменной или не окажется в родительской области видимости, то есть в цепочке областей видимости.Стоит отметить, что каждая подфункция копирует область видимости верхнего уровня, образуя цепочку областей видимости. Например:

var x = 1;
function demo() {
  var x = 2
  function demo2() {
    var x = 3;
    console.log(x);//3
  }
}

Насколько я понимаю, в приведенном выше коде область действия функции demo указывает на глобальную область (окно) и на себя, а область действия функции demo2 указывает на глобальную область (окно), демонстрацию и на себя. Кроме того, поиск области начинается снизу и просматривается до тех пор, пока не будет найдено окно глобальной области.Если глобальная область не найдена, будет сообщено об ошибке❌

Суть генерации замыкания 💯 В текущем окружении есть ссылка на родительский скоуп. Возьмем пример выше:👇

		var x = 1;
        function demo() {
            var x = 2

            function demo2() {
                console.log(x); 
            }
            return demo2;
        }
        var h = demo();
        h()   // 2

Здесь переменная h получит переменную родительской области и выведет 2. В текущей среде есть ссылка на demo2, которая ссылается только на область демонстрации окна и саму себя. Таким образом, demo2 может получить доступ к переменным в области демонстрации.

Приходит вопрос? Генерирует ли замыкания только при возврате функций?

Вернемся к сути замыкания:Просто позвольте ссылке на родительскую область существоватьТогда мы сможем сделать это 👇

		var demo2;
        function demo() {
            var x = 2

            demo2 = function () {
                console.log(x); 
            }
            
        }
        demo();
        demo2()    // 2

Сначала пусть выполняется внешняя функция, присваивает значение demo2, а это значит, что demo2 теперь имеет права доступа окна demo и свою область видимости, затем при поиске переменной x будет искать уровень за уровнем вверх, и найдет идентификатор в ближайшей демо-области. Просто верните результат, выведите 2.

🤭 Внешняя переменная demo2 здесь имеет ссылку на родительскую область видимости, поэтому генерируется замыкание, форма изменилась, но суть не изменилась.

Выражение закрытия 🤤

Разбираемся в сути, начинаем с реальной сцены, где может быть отражено существование замыкания❓

1️⃣Вернуть функцию, приведенное выше было примером

2️⃣ Передать как параметр функции

var a = 1;
function foo(){
  var a = 2;
  function baz(){
    console.log(a);
  }
  bar(baz);
}
function bar(fn){
  // 这就是闭包
  fn();
}
// 输出2,而不是1
foo();

3️⃣В таймерах, прослушивателях событий, запросах Ajax, межоконной связи, веб-воркерах или любой другой асинхронности, пока вы используете функции обратного вызова, вы фактически используете замыкания.

Следующие закрытия сохраняют только окно и текущую область.

// 定时器
setTimeout(function timeHandler(){
  console.log('2222');
},100)

// 事件监听
$('#div').click(function(){
  console.log('DIV Click');
})

4️⃣IIFE (немедленное выполнение функционального выражения) создает замыкание и сохраняет его全局作用域windowа также当前函数的作用域, так что это может быть глобальная переменная.

var x = 22;
(function IIFE(){
  // 输出22
  console.log(x);
})();

условия, которые производят

1️⃣Вложенность функций

2️⃣Внутренние функции ссылаются на данные (переменные/функции) внешних функций

уничтожить закрытие

Когда речь заходит об уничтожении замыканий, первое, о чем стоит поговорить, это механизм сборки мусора V8.

Механизм сборки мусора V8, я открою новую главу, чтобы рассказать об этом, когда подумаю об этом 🤭

Поговорим о механизме сборки мусора:

В javascript, если на объект больше не ссылаются, то объект будет утилизирован механизмом сборки мусора. Если два объекта ссылаются друг на друга и на них больше не ссылается третья сторона, то два объекта, которые ссылаются друг на друга, также будут переработаны.

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

Недостатком является то, что генерируется несколько приватных областей видимости (память кучи), которые не уничтожаются.Помимо влияния на производительность, если в настоящее время сохраненное замыкание или его родительская область видимости имеют html-элементы, это очень опасно 🚫

Уведомление

Закрытие сделает переменные в функции сохраненными в памяти, а потребление памяти очень велико, поэтому замыканием нельзя злоупотреблять, иначе это вызовет проблемы с производительностью веб-страницы и может вызвать утечку памяти в IE. Обходной путь — удалить все неиспользуемые локальные переменные перед выходом из функции.

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

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

Например, функции высшего порядка 🤭карринг

Суммировать

  • Личное понимание: Суть замыкания 💯 В текущей среде есть ссылка на родительскую область
  • Переменная, на которую указывает ссылка, не будет уничтожена до тех пор, пока не будет уничтожено замыкание.
  • Замыкания будут генерировать частные области видимости и потреблять много памяти, поэтому замыканиями нельзя злоупотреблять.Для ссылочных типов место хранения находится в памяти кучи, что вызовет утечку памяти, особенно когда в родительской области замыкания есть элементы html. , очень опасно 🚫
  • Замыкания несут область действия функции, которая их содержит, и поэтому занимают больше памяти, чем другие функции. Таким образом, анонимная функция может быть разыменована вручную, чтобы освободить память.
  • Сценарии приложения замыкания: модульность и каррирование

Ссылаться на

Откройте для себя силу замыканий в JavaScript

Руан Ифэн закрыт

Базовый операционный механизм замыканий JavaScript

Откройте для себя силу замыканий в JavaScript

Схематическая область действия и замыкания