Каждая функция в JavaScript имеет закрытие. И это одна из самых крутых особенностей языка JavaScript. Потому что без замыкания было бы трудно реализовать общие структуры, такие как обратные вызовы или обработчики событий.
Вы создаете закрытие всякий раз, когда вы определяете функцию. Затем, когда вы выполняете функции, их закрытия позволяют им получить доступ к данным в своих областях.
Это как вроде, когда автомобиль изготовлен (определен), он поставляется с несколькими функциями, такими как Начать
, ускорить
, Одеждаться
Отказ Эти функции автомобиля выполняются водителем каждый раз, когда они управляют автомобилем. Замыкание для этих функций определяются самим автомобилем и они близко к Переменные, которыми они должны работать.
Давайте сузим эту аналогию к ускорить
функция. Определение функции происходит, когда автомобиль изготовлен:
function accelerate(force) { // Is the car started? // Do we have fuel? // Are we in traction control mode? // Many other checks... // If all good, burn more fuel depending on // the force variable (how hard we're pressing the gas pedal) }
Каждый раз, когда водитель нажимает педаль газа, эта функция выполняется. Обратите внимание, как эта функция нуждается в доступе к большому количеству переменных для работы, включая свои собственные сила
Переменная. Но что более важно, ему нужны переменные вне его объема, которые контролируются другими функциями автомобиля. Это где закрытие ускорить
Функция (которую мы получаем с самой машиной), пригодится.
Вот что ускорить
Закрытие функции обещано ускорить
Функция сама:
Обратите внимание, что закрытие не дало ускорить
Функция Исправлено Значения для этих переменных, а скорее Разрешение Для доступа к тем значениям в то время выполняется ускорение функции.
Закрытия тесно связаны с Функция Scopes Так что понимание того, как эти спецификации помогут вам понять закрытие. Короче, самая важная вещь, чтобы понять о спецификации, это то, что когда вы Выполнить Функция, приведенная в частная функция, созданная и используется для процесса выполнения этой функции.
Затем эти функции вложены вложенные при выполнении функций из функций (которые вы будете делать все время).
Закрытие создано, когда вы Определить Функция – не при его выполнении. Затем, когда вы выполняете эту функцию, его уже определенное закрытие дает ему доступ ко всем функциям, доступными вокруг него.
В некотором смысле, вы можете подумать о приличиях как временных (глобальный объем – единственное исключение из этого), в то время как вы можете думать о том, что охватывают себя как постоянные.
Чтобы по-настоящему понять замыкания и роль, которую они играют в JavaScript, сначала нужно понять несколько других простых концепций о функциях JavaScript и их областями.
Прежде чем начать, обратите внимание, что я также создал интерактивную лабораторию для этого, которую вы можете работать через здесь Отказ
1 – Функции назначаются ссылкой на значение
Когда вы помещаете функцию в переменной, как это:
function sayHello() { console.log("hello"); }; var func = sayHello;
Вы назначаете переменную Func
Ссылка на функцию Сайхелло
, не копия. Здесь Func
это просто псевдоним в Сайхелло
Отказ Все, что вы делаете на псевдонимах, вы на самом деле будете делать на оригинальной функции. Например:
func.answer = 42; console.log(sayHello.answer); // prints 42
Недвижимость Ответ
был установлен напрямую на Func
и читать использование Сайхелло
, который работает.
Вы также можете выполнить Сайхелло
выполняя Func
псевдоним:
func() // prints "hello"
2 – Сцепы имеют всю жизнь
Когда вы вызываете функцию, вы создаете объем во время выполнения этой функции. Тогда этот прицел уходит.
Когда вы вызываете функцию во второй раз, вы создаете новую различную область во время второго выполнения. Тогда этот второй охват уходит так же.
function printA() { console.log(answer); var answer = 1; }; printA(); // this creates a scope which gets discarded right after printA(); // this creates a new different scope which also gets discarded right after;
Эти два облагания, созданные в примере выше, различны. Переменная Ответ
Здесь не разделяется между ними вообще.
Каждая функция обладает сроком службы. Они создаются, и они отбрасываются сразу. Единственным исключением к этому факту является глобальный объем, который не уходит до тех пор, пока приложение работает.
3 – замыкание охватывает несколько областей
Когда вы определяете функцию, создается закрытие
В отличие от спецификаций, закрытия создаются при у вас Определить Функция, не когда вы выполняете ее. Закрытия также не уходят после того, как вы выполняете эту функцию.
Вы можете получить доступ к данным в замыкании длиной после определения функции и после его выполнения.
Застежки охватывают все, что может получить доступную функцию. Это означает охват определенной функции, и все вложенные области между глобальной областью и определенной областью функций плюс мировой объем массы.
var G = 'G'; // Define a function and create a closure function functionA() { var A = 'A' // Define a function and create a closure function functionB() { var B = 'B' console.log(A, B, G); } functionB(); // prints A, B, G // functionB closure does not get discarded A = 42; functionB(); // prints 42, B, G } functionA();
Когда мы определяем ФункцияB
Здесь его созданное закрытие позволит нам получить доступ к объему ФункцияB
плюс объем Функция
Плюс глобальный объем.
Каждый раз, когда мы выполняем ФункцияB
мы можем получить доступ к переменным B
, А
и G
через ранее созданное закрытие. Однако это закрытие не дает нам копию этих переменных, а скорее ссылки на них. Так что если, например, значение переменной А
изменяется в какой-то момент после закрытия ФункцияB
создается, когда мы выполняем ФункцияB
После этого мы увидим новое значение, а не старая. Второй звонок в ФункцияB
Отпечатки 42, B, G
Потому что значение переменной А
был изменен на 42, а закрытие дало нам ссылку на А
, не копия.
Не путайте закрытие с областями
Для замыкания распространены в замешательстве с объемами, поэтому давайте не будем этого делать.
// scope: global var a = 1; void function one() { // scope: one // closure: [one, global] var b = 2; void function two() { // scope: two // closure: [two, one, global] var c = 3; void function three() { // scope: three // closure: [three, two, one, global] var d = 4; console.log(a + b + c + d); // prints 10 }(); }(); }();
В простом примере выше у нас есть три функции, и все они получают определенные и сразу же вызывают, поэтому все они создают призывы и замыкания.
Сфера функции Один ()
это его тело. Его закрытие дает нам доступ как к его объему, так и в глобальной области.
Сфера функции два ()
это его тело. Его закрытие дает нам доступ к его массу плюс объем функции Один ()
плюс глобальный объем
И аналогично, закрытие функции три ()
Дает нам доступ ко всем областям в примере. Вот почему мы смогли получить доступ к всем переменным в функции три ()
Отказ
Но отношение между областями и замыканиями не всегда просто так. Вещи становятся разными, когда определяющая и вызовов функций происходит в разных областях. Позвольте мне объяснить, что с примером:
var v = 1; var f1 = function () { console.log(v); } var f2 = function() { var v = 2; f1(); // Will this print 1 or 2? }; f2();
Как вы думаете, что приведен приведенный выше пример? Код прост, F1 ()
печатает значение V
, который 1 на глобальном масштабе, но мы выполняем F1 ()
внутри F2 ()
, который имеет другой V
это равно 2. Тогда мы выполняем F2 ()
Отказ
Будет ли этот код печатать 1 или 2?
Если вы искушаете сказать 2, вы будете удивлены. Этот код на самом деле будет печатать 1. Причина в том, что причина в том, что области и замыкания различны. console.log
линия будет использовать закрытие F1 ()
, который создан, когда мы определяем F1 ()
, что означает закрытие F1 ()
дает нам доступ только к объему F1 ()
Плюс глобальный объем. Примера, где мы выполняем F1 ()
не влияет на это закрытие. На самом деле, закрытие F1 ()
не даст нам доступ к объему F2 ()
вообще. Если вы удалите глобальный V
Переменная и выполните этот код, вы получите ссылочную ошибку:
var f1 = function () { console.log(v); } var f2 = function() { var v = 2; f1(); // ReferenceError: v is not defined }; f2();
Это очень важно понимать и помнить.
4 – Закрытия прочитали и пишут доступ
Поскольку замыкание дают нам ссылки на переменные в областях, доступ, который они дают нам, значит как читать, так и писать, а не только прочитать.
Посмотрите на этот пример:
function outer() { let a = 42; function inner() { a = 43; } inner(); console.log(a); } outer();
Внутренний ()
Функция здесь, когда определяется, создает закрытие, которое дает нам доступ к переменной А
Отказ Мы можем прочитать и изменить эту переменную, и если мы сделаем его изменим, мы будем изменять фактические А
Переменная в внешний ()
сфера.
Этот код будет печать 43 потому что мы использовали Внутренний ()
Закрытие функции, чтобы изменить внешний ()
Функция переменной.
Это на самом деле, почему мы можем изменить глобальные переменные везде. Все замыкания дают нам как доступны и получать доступ к всем глобальным переменным.
5 – замыкание может поделиться насаждениями
Поскольку замыкание дают нам доступ к вложенным областям в то время, когда мы определяем функции, когда мы определяем несколько функций в том же объеме, что объем совместно используется между всеми созданными закрытиями, и, конечно, из-за этого, глобальный объем всегда обделяется среди всех закрытие.
function parent() { let a = 10; function double() { a = a+a; console.log(a); }; function square() { a = a*a; console.log(a); } return { double, square } } let { double, square } = parent(); double(); // prints 20 square(); // prints 400 double(); // prints 800
В приведенном выше примере у нас есть родитель ()
Функция с переменной А
Установите на 10. Мы определяем две функции в этом родитель ()
Область функции, Двойной ()
и квадрат ()
Отказ Закрытия, созданные для Двойной ()
и квадрат ()
Оба поделитесь объемом родитель ()
Функция Отказ Поскольку оба Двойной ()
и квадрат ()
изменить значение А
, когда мы выполняем последние 3 строки, мы удваиваем А
(Создание A
), затем квадрат, что удвоилось ценность (создание A
), затем удвоивайте, что в квадрате значение (создание A
).
Один последний тест
Давайте теперь проверим ваше понимание закрытия до сих пор. Прежде чем выполнить следующий код, попробуйте угадать, что он будет печать:
let a = 1; const function1 = function() { console.log(a); a = 2 } a = 3; const function2 = function() { console.log(a); } function1(); function2();
Я надеюсь, что вы получили это правильно, и я надеюсь, что эти простые понятия помогут вам по-настоящему понять значительную роль.
Спасибо за прочтение.
Изучение реагировать или узел? Оформить заказ моих книг: