Замыкания в JavaScript на примерах кода

Замыкания в JavaScript на примерах кода



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

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

Что такое замыкание?

Замыкание- чрезвычайно мощное свойство JavaScript( и большинства языка программирования). Как определено в MDN:

Замыкания - это функции, которые ссылаются на независимые(свободные) переменные. Другими словами, функция, определенная в замыкании, “запоминает” среду, в которой она была создана


Примечание. Свободные переменные- это переменные, которые не объявляются локально и не передаются в качестве параметра.

Давайте рассмотрим несколько примеров:

Пример 1:

function numberGenerator() {

  // Local “free” variable that ends up within the closure

  var num = 1;

  function checkNumber() { 

    console.log(num);

  }

  num++;

  return checkNumber;

}

var number = numberGenerator();

number(); // 2

В приведенном выше примере функция numberGenerator создает локальную “свободную” переменную num(число) и checkNumber(функция, выводящую num на консоль).

У функции checkNumber нет собственных локальных переменных, однако у нее есть доступ к переменным внутри внешней функции, numberGenerator, из-за замыкания.

Следовательно, он может использовать переменную num, объявленную в numberGenerator, чтобы успешно вывести ее на консоль даже после возврата  numberGenerator.

Пример 2:

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

function sayHello() {

  var say = function(){ console.log(hello); }

  // Local variable that ends up within the closure 

  var hello = 'Hello, world!';

  return say;

}

var sayHelloClosure = sayHello(); 


sayHelloClosure(); // ‘Hello, world!’

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

(Не волнуйтесь, я объясню, что означает “область охвата” позже в статье. А пока просто действуйте!)


Понимание высокого уровня

Эти примеры иллюстрируют “какие” замыкания на высоком уровне. 

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

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

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

Начнем с всеобъемлющего контекста, в котором запускается функция, известного как “контекст выполнения”.


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

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


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



Report Page