Давайте лучше поймем, что такое замыкание.
Концепция закрытия была для меня сложной, но я думаю, что у меня был ага-момент для закрытия, и я хочу поделиться им здесь.
Моя цель – дать вам понять, что такое закрытие, к концу этой статьи.
Я собираюсь поговорить о том, что такое закрытие. Я люблю объяснять простым языком.
Итак, что такое закрытие?
Замыкание — это (явление), когда блок кода может получить доступ к объекту, находящемуся за пределами блока.
Прежде чем мы перейдем к заключению, я хотел бы кратко объяснить область.
Рассмотрим этот пример.
{ let myName = 'Jinsung'; } console.log(myName); // ReferenceError: myName is not defined
`{ }` образует блок (они кажутся знакомыми, потому что у каждой функции есть свой блок!) и каждый блок имеет свою область действия.
В этом блоке определена переменная myName
, и когда я печатаю переменную myName
, она показывает ошибку.
Это происходит потому, что любые переменные или функции, созданные в блоке, доступны ТОЛЬКО в этом блоке.
Тогда как насчет этого примера?
{ let myName = 'Jinsung'; console.log(myName); // prints 'Jinsung' }
Теперь этот код работает,
потому что console.log()
находится внутри того же блока, где был определен myName
, и он может получить доступ к myName
.
Эти две строки кода находятся в одной области.
Давайте посмотрим на этот пример.
let fruits = {'apple':10, 'orange':5}; function eatOneApple(){ fruits['apple'] -= 1; } eatOneApple(); console.log(fruits); // {'apple':9, 'orange':5}
Переменная fruits
определена в глобальной области.
Когда переменная определена в простом файле javascript (она не находится внутри какого-либо блока), она называется глобальной переменной, а глобальная переменная имеет глобальную область действия.
Это означает, что переменная fruits
может быть доступна в любом месте того же файла.
И функция eatOneApple()
имеет `{ }`(блок), и этот блок имеет область видимости функции или локальную область видимости.
Таким образом, глобальная область действия определенно больше, чем область действия функции (локальная область действия), а глобальная область содержит область действия функции (локальная область действия).
Вот когда происходит закрытие.
let fruits = {'apple':10, 'orange':5}; function eatOneApple(){ fruits['apple'] -= 1; } eatOneApple(); console.log(fruits); // {'apple':9, 'orange':5}
Переменная fruits
доступна в области видимости функции, несмотря на то, что переменная fruits
находится в глобальной области видимости.
eatOneApple() может получить доступ к объекту fruits и изменить объект fruits, который остается даже после завершения выполнения функции.
Переменная fruits
изменена навсегда, потому что eatOneApple()
изменила fruits
из своей области действия.
Вернемся к определению, которое мы видели ранее,
Замыкание — это (явление), когда блок кода может получить доступ к объекту, находящемуся за пределами блока.
Надеюсь, это поможет вам лучше понять это.
Теперь давайте перейдем к тому, почему люди говорят о закрытии.
Очень часто люди часто говорят о закрытии в этом конкретном контексте.
Рассмотрим этот пример.
function prepareToTalk(myName){ let introduce = function(toWhom){ console.log(`hello ${toWhom}, my name is ${myName}`); } return introduce; }
Что здесь происходит?
Я создал функцию prepareToTalk()
, которая принимает строковую переменную myName
,
и внутри функции я создал еще одну функциональную переменную с именем introduce
.
А prepareToTalk()
возвращает ссылку на функцию introduce
.
Хорошо, так как это закрытие?
Мы знаем, что myName
передается в качестве аргумента внешней функции prepareToTalk
.
Это означает, что myName
находится внутри внешней области видимости функции prepareToTalk
,
но анонимная функция (function(toWhom)
) назначается переменной introduce
, как в примере ниже.
let introduce = function(toWhom){ console.log(`hello ${toWhom}, my name is ${myName}`); }
Переменная introduce
имеет собственную область внутренней функции, а в области внутренней функции она использует переменные toWhom
и myName
.
Переменная myName
НЕ находится во внутренней функции, а находится во внешней функции prepareToTalk()
,
но доступ к myName
осуществляется во внутренней области функций, которая есть у introduce
.
Это делает его примером закрытия.
Как и когда использовать замыкание?
Продолжая приведенный выше пример,
function prepareToTalk(myName){ let introduce = function(toWhom){ console.log(`hello ${toWhom}, my name is ${myName}`); } return introduce; } let jinsung = prepareToTalk('Jinsung'); console.log(jinsung); // ??
Что произойдет, если мы вызовем prepareToTalk()
и назначим его переменной jinsung
?
[Function: introduce]
Переменная jinsung
возвращает объект функции с именем introduce
.
Это похоже на следующий пример.
function print(name) { console.log(name); return name; } const printName = print; console.log(printName); // [Function: print]
Переменная printName
имеет значение ссылки на функциональный объект print
.
Это все, что он делает. Он НЕ вызывает функцию print
.
Чтобы вызвать print
, мы ставим «()» рядом с printName
.
Так же, как пример ниже.
function print(name) { console.log(name); } const printName = print; printName('JSK'); // prints 'JSK'
Возвращаясь к исходному примеру,
function prepareToTalk(myName){ let introduce = function(toWhom){ console.log(`hello ${toWhom}, my name is ${myName}`); } return introduce; } let nabi = prepareToTalk('Nabi'); // [Function: introduce] const nabiToJinsung = nabi('Jinsung'); nabiToJinsung; // prints 'hello Jinsung, my name is Nabi'
В этой строке кода
const nabi = prepareToTalk('Nabi');
Строка «Наби» передается в качестве аргумента в функцию prepareToTalk()
и присваивается переменной myName
.
переменная
myName
находится во внешней функцииprepareToTalk()
,
и доступен во внутренней функциональной переменной
introduce
в любое время.
(определение замыкания)
Когда мы звоним prepareToTalk(‘Nabi’)
,
он НЕ возвращает какое-либо вычисленное значение или что-то еще, он возвращает только ссылку на объект функции с именем introduce
.
Возвращаемое значение: [Function: introduce]
Поскольку prepareToTalk()
возвращает ссылку на функцию introduce
, переменная nabi
также возвращает ссылку на функцию introduce
.
Чтобы вызвать introduce
, мы можем поставить `( )` рядом с nabi
.
nabi('Jinsung'); // calling introduce() function with 'Jinsung' string argument.
И чтобы присвоить это значение переменной, мы можем написать
const nabiToJinsung = nabi('Jinsung'); // prints 'hello Jinsung, my name is Nabi'
Мы также можем попробовать создать разные объекты с одним и тем же строковым значением «Наби», назначенным myName
.
function prepareToTalk(myName){ let introduce = function(toWhom){ console.log(`hello ${toWhom}, my name is ${myName}`); } return introduce; } let nabi = prepareToTalk('Nabi'); // [Function: introduce] const nabiToJinsung = nabi('Jinsung'); // // prints 'hello Jinsung, my name is Nabi' const nabiToHarry = nabi('Harry'); // prints 'hello Harry, my name is Nabi' const nabiToJacob = nabi('Jacob'); // prints 'hello Jacob, my name is Nabi' const nabiToLee = nabi('Lee'); // prints 'hello Lee, my name is Nabi'
Переменные
nabiToHarry
,nabiToJacob
иnabiToLee
совместно используют одну и ту же внешнюю переменнуюmyName
в своей внешней функцииprepareToTalk()
.
Изменение переменной
myName
изменит значение всех связанных с ней переменных.
function prepareToTalk(myName){ let introduce = function(toWhom){ console.log(`hello ${toWhom}, my name is ${myName}`); } return introduce; } let nabi = prepareToTalk('🐱MEOW🐱'); // changed from 'Nabi' to '🐱MEOW🐱' const nabiToJinsung = nabi('Jinsung'); // // prints 'hello Jinsung, my name is 🐱MEOW🐱' const nabiToHarry = nabi('Harry'); // prints 'hello Harry, my name is 🐱MEOW🐱' const nabiToJacob = nabi('Jacob'); // prints 'hello Jacob, my name is 🐱MEOW🐱' const nabiToLee = nabi('Lee'); // prints 'hello Lee, my name is 🐱MEOW🐱'
Надеюсь, теперь вы понимаете, что такое замыкание лучше.
Если ты этого не понял,
напишите мне на [email protected]
или напишите мне на linkedin.
Я вернусь к вам, как только смогу.