Руководство по закрытию JavaScript

Введение Замыкания - это несколько абстрактная концепция языка JavaScript, которая проникает в программирование на стороне компилятора. Однако понимание того, как JavaScript интерпретирует функции, вложенные функции, области видимости и лексические среды, необходимо для использования всего его потенциала. В этой статье мы попытаемся демистифицировать упомянутые концепции и предоставить простое руководство по закрытию JavaScript. Что такое закрытие? Сначала давайте взглянем на официальное определение закрытия в MDN:> Замыкание - это t

Вступление

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

В этой статье мы попытаемся демистифицировать упомянутые концепции и предоставить простое руководство по закрытию JavaScript .

Что такое закрытие?

Сначала давайте взглянем на официальное определение закрытия в MDN:

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

Проще говоря, замыкание - это функция, которая имеет доступ к области внешней функции. Чтобы понять это, давайте посмотрим, как области видимости работают в JavaScript.

Область видимости в JavaScript

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

  • Global Scope - переменные, определенные вне функции. К переменным в этой области можно получить доступ и изменить из любой точки программы, отсюда и название «глобальные».

  • Local Scope - переменные, определенные внутри функции. Эти переменные относятся к той функции, в которой они определены, поэтому они называются «локальными».

Давайте посмотрим на глобальную и локальную переменные в JavaScript:

 let name = "Joe"; 
 
 function hello(){ 
 let message = "Hello"; 
 console.log(message + " " +name); 
 } 

В приведенном выше примере область действия name глобальна, т. Е. К нему можно получить доступ откуда угодно. С другой стороны, message определяется внутри функции, его область действия является локальной для функции hello() .

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

На

 function outer(){ 
 let x = 10; 
 
 function inner() { 
 let y = 20; 
 console.log(x); 
 } 
 
 inner(); 
 console.log(y) 
 } 
 
 outer(); 

Этот код приводит к:

 10 
 error: Uncaught ReferenceError: y is not defined 

Функция inner() может ссылаться на x поскольку она определена в функции outer() . Однако console.log(y) в функции outer() не может ссылаться на y поскольку она определена в области видимости функции inner()

Кроме того, в этом сценарии:

 let x = 10; 
 
 function func1(){ 
 console.log(x); 
 } 
 
 function func2() { 
 let x = 20; 
 func1(); 
 } 
 
 func2(); 

Результатом будет:

 10 

Когда мы вызываем func1() из func2() , мы получаем переменную x с локальной областью видимости. Однако эта переменная совершенно не имеет отношения к func1() поскольку она недоступна в func1() .

Таким образом, func1() проверяет, доступна ли глобальная переменная с этим идентификатором, и использует ее, в результате чего получается значение 10 .

Закрытие под капотом

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

  • Локальная область видимости - доступ к переменным в ее собственной области видимости.
  • Область видимости родительской функции - доступ к переменным внутри ее родительской функции
  • Global Scope - доступ к глобальным переменным

Давайте посмотрим на закрытие в действии, создав функцию, которая возвращает другую функцию:

 function outer() { 
 let x = 3 
 return function inner(y) { 
 return x*y 
 } 
 } 
 
 let multiplyByThree = outer(); 
 
 console.log(multiplyByThree(2)); 

Это приводит к:

 6 

Если мы сделаем:

 console.log(multiplyByThree); 

Нас встречают:

 function inner(y) { return x * y; } 

Давайте рассмотрим код шаг за шагом, чтобы увидеть, что происходит под капотом:

  1. Функция outer() определена в глобальной области видимости.
  2. outer() вызывается, и он возвращает функцию, которая назначена multiplyByThree .
    1. outer() создается новый контекст выполнения.
      • Переменная x установлена на 3.
    2. Возвращает функцию с именем inner() .
    3. Ссылка на inner() присваивается multiplyByThree .
    4. Когда внешняя функция завершает выполнение, все переменные в ее области удаляются.
  3. Результат вызова функции multiplyByThree(2) записывается в консоль.
    1. inner() вызывается с 2 в качестве аргумента. Итак, y установлено на 2 .
    2. Поскольку inner() сохраняет цепочку областей видимости своей родительской функции, во время выполнения она все еще будет иметь доступ к значению x .
    3. Он возвращает 6 что записывается в консоль.

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

Визуализация замыканий

Замыкания можно визуализировать через консоль разработчика:

 function outer() { 
 let x = 3 
 return function inner(y) { 
 return x*y 
 } 
 } 
 
 let multiplyByThree = outside(); 
 console.dir(multiplyByThree); 

Выполнив приведенный выше код в консоли разработчика, мы видим, что у нас есть доступ к контексту inner(y) . При ближайшем рассмотрении мы видим, что часть его контекста представляет собой [[Scopes]] , который содержит все три области, о которых мы говорили.

И вот, массив областей видимости содержит область видимости родительской функции, которая содержит x = 3 :

Элемент закрытия в консолиразработчика{.ezlazyload}

Общие варианты использования

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

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

Давайте посмотрим на следующий пример, чтобы лучше понять это:

 const balance = (function() { 
 let privateBalance = 0; 
 
 return { 
 increment: function(value){ 
 privateBalance += value; 
 return privateBalance; 
 }, 
 decrement: function(value){ 
 privateBalance -= value; 
 return privateBalance; 
 }, 
 show: function(){ 
 return privateBalance; 
 } 
 } 
 })() 
 
 console.log(balance.show()); // 0 
 console.log(balance.increment(500)); // 500 
 console.log(balance.decrement(200)); // 300 

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

Заключение

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

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

comments powered by Disqus