Все еще беспокоитесь о том, что интервьюер спрашивает о закрытии?

JavaScript
Все еще беспокоитесь о том, что интервьюер спрашивает о закрытии?

Статья с подведением итогов замыканий в инете протухла.Не смею сказать насколько ххх эта статья,это просто личное понимание и резюме. Просто взгляните на чиновников, и Великий Бог также надеется внести больше исправлений. Эта статья завершается «JavaScript Ninja Cheats», «JavaScript, которого вы не знаете».

Адрес блога серии: https://github.com/Nealyang/YOU-SHOULD-KNOW-JS

Стек технологий персонального реагирования Amway + экспресс + руководство по личному блогу по борьбе с мангустамиReact-Express-Blog-Demo

предисловие

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

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

Одним словом, замыкания, которые вы должны освоить.

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

Объем, о котором мы здесь говорим, стоит лексического объема. Лексическая область — это область, определенная на лексической фазе. Другими словами, это определяется тем, где вы пишете области переменных и блоков при написании кода. Следовательно, объем останется неизменным при лексическом анализе. (Движок JavaScript примерно проходит три этапа: сегментация слов/лексический анализ, синтаксический анализ/анализ грамматики и генерация кода при запуске кода JavaScript).

Старые правила, смотрите код (то есть там много кода~~)

function foo(a) {
  var b = a*2;
  function bar(c) {
    console.log(a,b,c);
  }
  bar(b*3);
}
foo(2);//2 4 12

В этом примере есть три области, вложенные по одному уровню за раз, как показано на рисунке:

Скриншот из «JavaScript, которого вы не знаете»

Первая часть содержит всю область, которая является глобальной областью. который содержит идентификатор: foo

Часть вторая содержит область действия, созданную foo, которая содержит: a, bar и b

Бар области содержит некоторые из трех созданных, которые включают в себя: C

Включение этих областей пузырьков обеспечивает двигатель достаточно информации о местоположении. В приведенном выше коде, когда двигатель выполняет Console.log, он ищет A, B и C. Это сначала в самых внутренних объеме, который является функцией стержня (...). Двигатель не может найти переменную A на этом уровне объема, поэтому двигатель перейдет к предыдущему вложенную область foo (...), чтобы найти его, и если он его найдет, он будет использоваться.

Если и a, и c существуют в области действия bar(...), foo(...), console.log(...) не нужно искать переменную во внешней области действия foo.

Где бы ни вызывались функции и как бы они ни вызывались, их лексическая область видимости определяется только тем, где функция объявлена. Поиск с лексической областью действия будет искать только идентификаторы первого уровня, такие как a, b и c.

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

Концепция закрытия

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

Понятия в «Полном руководстве по JavaScript»

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

Понятия в «Полном руководстве по JavaScript»

Замыкание — это функция, которая имеет доступ к переменным в области видимости другой функции.

Концепции JavaScript Ninja Читы

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

Концепции в JavaScript, о которых вы не знали

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

личное понимание

Замыкание — это функция, функция, которая может обращаться к переменным внутри других функций и манипулировать ими. Также можно сказать, что это функция, определенная внутри функции. Поскольку в JavaScript нет динамической области видимости, а суть замыканий — в статической области видимости (правило статической области видимости ищет объявление переменной, когда оно зависит от статических отношений между блоками в исходной программе), поэтому доступ к функции всегда происходит, когда мы определяем это Область действия, или лексическая область действия. Таким образом, закрытие будет реализовано.

Наша общая форма закрытия заключается в том, что функция оборачивает функцию b, а затем функция возвращает функцию b, так что функция b все еще может получить доступ к области действия функции, когда она выполняется вне функции a. Реальная сила замыканий отражается в том факте, что «функция b выполняется вне функции».

вопросы существа

function outer() {
  var a = 2;
  function inner() {
    console.log(a);//2
  }
  inner();
}
outer();

Основываясь на лексической области видимости и правилах поиска, внутренняя функция может получить доступ к переменной a, определенной внутри внешней. Технически это замыкание. Но можно также сказать, что это не так, потому что метод, используемый для объяснения ссылки inner на a, — это правила поиска лексической области видимости, а эти правила — только часть замыкания.

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

function outer() {
  var a = 2;
  function inner() {
    console.log(a);
  }
  return inner;
}
var neal = outer();
neal();//2

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

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

inner() уже содержит ссылку на эту область, и эта ссылка называется замыканием.

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

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

var fn;
function foo() {
  var a = 2;
  function baz() {
    console.log(a);
  }
  fn = baz;
}

function bar() {
  fn();
}
foo();
bar();

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

var outerValue = 'ninja';
var later;
function outFunction() {
  var innerValue = 'Neal';
  function innerFunction(param){
      console.log(outerValue,innerValue,param,tooLate);
  }
  later = innerFunction;
}
console.log('tooLate is',tooLate);
outFunction();
later('Nealyang');
var tooLate = 'Haha';
later('Neal_yang');

//tooLate is undefined
//ninja Neal Nealyang undefined
//ninja Neal Neal_yang Haha

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

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

Замыкания повсюду в коде

function wait(message) {
     setTimeout( function timer() {
         console.log( message ); }, 1000 ); }
wait( "Hello, closure!" );

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

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

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

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

Использование замыканий в классических циклах for

for (var i=1; i<=5; i++) {
     setTimeout( function timer() {
         console.log( i ); }, i*1000 ); }

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

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

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

Таким образом, наш код изменяется следующим образом:

for (var i=1; i<=5; i++) { (function() {
         setTimeout( function timer() {
             console.log( i ); }, i*1000 ); })(); }

но! ! ! Вы также обнаружили, что это не фамилия, не приведет ли IIFE к закрытию? Да, но если область закрытия, созданная этим IIFE, допускает значение NULL, какой смысл ее инкапсулировать? Так что нужно что-то существенное, давайте использовать его.

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

Конечно, мы можем использовать let in es6 для решения вышеуказанной проблемы. Но я не буду здесь вдаваться в подробности. Вы можете сами погуглить.

модуль

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

Просто посмотрите на пример напрямую, операция более обычная

function foo() {
    var something = "cool"; 
    var another = [1, 2, 3];
    function doSomething() {
         console.log( something ); 
    } 
    function doAnother() {
         console.log( another.join( " ! " ) ); 
    }
    return {
        doSomething:doSomething,
        doAnother:doAnother
    }
}

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

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

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