В процессе фронтенд-обучения мы неизбежно столкнемся со многими проблемами, поэтому сегодня мы поговорим о двух вопросах с точки зрения новичка:
Что такое замыкание?
Каковы функции замыканий?
На самом деле, когда мы изучаем JavaScript, замыкания встречаются повсюду, вам просто нужно уметь их распознавать и принимать. Замыкания не являются инструментом, для использования которого требуется изучение нового синтаксиса или шаблона. Замыкания являются естественным следствием написания кода, основанного на лексической области видимости. Нам редко приходится намеренно создавать замыкания при написании кода.
Я думаю, что многие друзья в это время уже бормочут в своих сердцах: что это за лексический объем? Не паникуйте, просто слушайте меня медленно. Короче говоря, лексический объем — это объем, определенный на лексическом этапе. Другими словами, лексическая область видимости определяется тем, где вы размещаете переменные и области уровня блока при написании кода, поэтому область видимости остается неизменной, когда лексический анализатор обрабатывает код (большую часть времени). —— «JavaScript, который вы не знаете».
Давайте сначала рассмотрим пример:
function test(){ вар обр = [] for(var i=0;i<10;i++){ arr[i]=function(){ console.log(я); } } возвращение } вар myArr = тест() // мойАрр[0]() // мойАрр[1]() // ... for(var j = 0; j < 10; j++){ мойАрр[j]() } //Чтобы избежать утомления, здесь используется второй цикл для вызова функции из первого цикла в тестовой функции и вывода десяти результатов.
Давайте сначала проанализируем этот код: Когда этот код выполняется, в соответствии со здравым смыслом. следует проанализировать. Он последовательно выводит десять чисел от 0 до 9, но выполнение цикла for не требует времени (не учитывается в микросекундах). Когда функция test возвращает arr, существует 10 function(){console. );}, функция в массиве в это время не выполняется. Когда var myArr = test() вызывает тестовую функцию, поскольку время выполнения цикла for игнорируется, i в это время уже равно 10, так что же такое? напечатано 10 из 10.
Я думаю, сейчас кто-то спросит, какое отношение это имеет к замыканию, о котором мы собираемся говорить? Итак, если мы немного изменим этот код и превратим его в аккумулятор, как мы сможем это реализовать?
Я верю, что в это время найдутся важные шишки, которые скажут: разве не все просто?
Измените определение var на определение let, чтобы первый цикл for стал областью действия на уровне блока, а затем он мог стать аккумулятором. Конечно, проблем нет,
но мы сегодня говорим о том, как реализовать аккумулятор в ES5. Затем давайте взглянем на следующий код:
function test(){ вар обр = [] for(var i=0;i<10;i++){ (функция(j){ арр[j]=функция(){ console.log(j); } })(я) } возвращение } вар myArr = тест() for(var j = 0; j < 10; j++){ мойАрр[j]() }
Осторожные друзья обязательно обнаружат, что это изменение тела функции в цикле на самовыполняющуюся функцию, но результатом вывода в этот раз является последовательный вывод десяти чисел от 0 до 9, и это включает в себя пакет замыкания, когда мы начнем выполнять этот код, второй цикл for будет вызываться десять раз. При выполнении каждой самоисполняющейся функции будет создан объект AO самоисполняющейся функции. В этой самоисполняющейся функции есть объект AO. Имя атрибута — j. Обычно после выполнения функции выполнения ее объект AO должен быть уничтожен. Однако при выполнении myarr[j] () объект AO arr[j] находится в верхней части цепочки областей действия. теперь я искал имя атрибута j, но не нашел его по цепочке областей и нашел его в объекте AO самоисполняющейся функции. Поэтому, когда самоисполняющаяся функция завершается, это AO. объект не будет переработан механизмом сборки мусора, иначе при выполнении myarr[j]() будет сообщено об ошибке и будет сформировано замыкание.
Давайте возьмем еще один пример
функции a(){. функция б(){ вар bbb = 234 console.log(ааа); } вар ааа = 123 return b // b родился в a, но был сохранен} варглоб = 100 вар демо = а()Сначала мы используем предварительную компиляцию для анализа кода
demo()
. Сначала определите глобальный объект GO и найдите объявление глобальной переменной. Объявление переменной будет использоваться в качестве имени атрибута GO. не определено. Найдите его в глобальном объявлении. Для объявления функции имя функции используется в качестве имени атрибута объекта GO, а значение присваивается телу функции. На данный момент это должно быть GO{ glob: undefined --->100; demo: undefined; a: fa(){} }. Затем создайте AO{ aaa: undefined --->123;b: fb() для. function a {} } и, наконец, предварительно скомпилируйте функцию b в функции a, чтобы создать AO b { b: undefined --->234}, в этот момент порядок цепочки областей равен 1. Объект AO функции b; 2. Объект AO функции a 3. Глобальный объект GO. Когда мы печатаем aaa в функции b, мы начинаем с вершины цепочки областей действия. Если в объекте AO функции b нет aaa, мы будем искать вниз по цепочке областей видимости, чтобы найти AO функции второго уровня a. Цель состоит в том, чтобы найти значение aaa как 123 и вывести результат.
Если бы мы не анализировали это с точки зрения предварительной компиляции, мы бы подумали, что aaa должен сообщить об ошибке в это время. Когда выполняется var demo = a(), когда выполнение функции a заканчивается, тогда объект AO, соответствующий. a должен быть уничтожен. Согласно анализу здравого смысла: когда мы выполняем демонстрацию, цепочка областей должна создать объект AO и объект GO b. В настоящее время существует только объект AO b и нет объекта AO a. Значение aaa не следует распечатывать, но в настоящее время значение aaa равно 123, что означает, что объект AO a не был уничтожен, так почему? Причина в том, что здесь создается замыкание. Когда выполнение var demo = a() завершится, механизм сбора мусора спросит: «Брат, функция, я думаю, ты закончил ее выполнение. Можно ли мне освободить твою рабочую память». ?, но в это время функция a могла только беспомощно покачать головой и сказать: «Брат, я не уверен, завершил ли я выполнение. После того, как я выполнил его, я создал b, но b не находится под моим контролем, поэтому я это делаю». не уверен, был ли вызван b, поэтому не уверен, что я завершил выполнение. Механизм сбора мусора задумался об этом. Поскольку вы не знаете, я не буду его перерабатывать. Я должен сообщить об ошибке, поэтому в настоящее время объект AO не перерабатывается.
Я полагаю, что благодаря этим двум примерам вы уже имеете общее представление о замыканиях. Далее давайте поговорим о функциях замыканий.
Функциязамыкания
заключается
- можно
- в реализации общедоступных переменных. Например: аккумулятор (3.js)
- кэшировать
- для достижения инкапсуляции, приватизации
- и модульной разработки атрибутов для предотвращения загрязнения глобальных переменных.
3.js).
количество вар = 0 функция добавить() { количество возвращаемых значений++ } console.log(добавить()); console.log(добавить()); console.log(add());
Это относительно распространенный код накопления, но если во время нашей стажировки или даже на работе компания требует от вас инкапсулировать аккумулятор в модульный код, то в этот раз, ради модуль Мы стараемся избегать определения глобальных переменных, насколько это возможно, но как мы можем добиться этого, не определяя глобальные переменные? На данный момент мы можем использовать замыкания;
функция добавить() { количество вар = 0 функция а() { ++счет console.log(счет); } вернуть } вар рез = добавить() рез() рез() //После завершения функции добавления объект AO add не уничтожается, поскольку после выполнения функции добавления возвращаемый a образует замыкание, не зная, было ли оно вызвано, поэтому его можно инкапсулировать в модуль без использования глобальные переменные.
Итак, это некоторые мои личные мнения о замыканиях и их функциях. В настоящее время я имею лишь поверхностное представление о замыканиях. После последующего изучения и улучшения будут последующие статьи о замыканиях. Спасибо за просмотр. исправляйтесь и вместе добивайтесь прогресса.