string_js

Замыкание в JavaScript объясняем за пять минут

Наши соц. сети: instagram, fb, tg

Замыкание - небольшая фича, которая решает кучу проблем.

«Объясни плиз замыкания (или по-молодежному говорят CLOSURE) в javascript и как его вообще юзать?» - это вопрос, который возникал почти во всех моих интервью. Неважно, кто это был, бэкендер или фронтендер. Просто жизненно необходимо было знать что такое замыкание и как его юзать. Иногда человек, который брал у меня интервью и задавал этот вопрос, даже не понимал, что такое замыкание и с чем его едят. Цель этой статьи - демистифицировать (не простое словечко для НЕ гуманитария, простыми словами - прояснить) замыкания. Это очень просто и полезно, если вы внимательно прочтете и поймете. Большинство front-end-разработчиков и раньше его использовали сознательно или неосознанно. Замыкание - это просто функция, которая по-прежнему имеет доступ к закрытым членам своих родителей (область видимости) даже после закрытия родительской функции. Ну, как же нам его юзать сейчас, когда мы знаем, что это такое? Давайте реализуем функцию, где замыкание - лучшее решение, которое я могу придумать прямо сейчас. Вам была предоставлена честь создать самый красивый сайт за всю историю человечества. Одной из самых замечательных функций сайта является возможность юзерам кликать на знаменитую кнопку «High-Five». Когда пользователь действительно доволен содержанием сайта, он кликает на эту самую кнопочку, и значение пяти верхних значений увеличивается на 5, юзер может жать на эту кнопку снова и снова, потому что ваш сайт такой крутой. Давайте напишем код. Во-первых, давайте создадим функцию с именем giveHighFive
function giveHighFive()
{
    var highFiveCount = 0;
    highFiveCount += 5
    return highFiveCount;
}
 
Наше событие onclick кнопки привязано к этой функции, поэтому, когда юзер кликает ее в первый раз, она отображает 5. При следующем клике этой кнопки переменная highFiveCount будет сброшена до 0, потому что ее область видимости вне функции giveHighFive, то есть невидима. Если вы не знакомы с областью видимости, это относится к самой видимости переменной или функции. Есть два вида области видимости. Локальный и глобальный. Локальный ограничен тем, где вы его объявляете (блоком кода), а глобальный означает, что он доступен в любой точке вашей программы Почему бы не использовать глобальную переменную? Хорошо, я рад, что вы спросили. Допустим, мы используем глобальную переменную. Давайте теперь сделаем нашу переменную highFiveCount глобальной.
//global score
var highFiveCount = 0;
function giveHighFive()
{
    highFiveCount += 5;
    return highFiveCount
}
Если наш пользователь теперь нажимает кнопку несколько раз, счетчик будет увеличиваться правильно. Однако теперь наша переменная может быть изменена любым скриптом на странице, потому что глобальные переменные принадлежат объекту window. Часть вашей программы может изменить ваше значение highFiveCount. Это не то, чего мы пытаемся достичь. Мы хотим убедиться, что значение нашей переменной может быть изменено только с помощью нашего метода. Мы собираемся сделать нашу переменную локальной для нашей функции, чтобы она была видна только внутри нашей функции. Мы только что решили проблему с нашей переменной, получающей сброс, мы также убедились, что доступ к ней ограничен только нашей функцией, но есть еще одна проблема. Область видимости глобальной переменной немедленно отбрасывается, как только вы уходите со страницы. Это означает, что если бы наш юзер зашел на другую страницу нашего сайта, мы бы, к сожалению, потеряли бы только что полученные high-fives.
function funcA()
{
    var a = "I'm a";
    //funcB is visible to funcA
    console.log(funcB());
    //funcC & funcD are invisible to funcA.
    function funcB()
    {
        var b = "I'm b";
        //has access to variable a & b,but not c.
        function funcC()
        {
             var c = "I'm c";
             console.log(a + b);
        }
        function funcD()
        {
             console.log(funcC());
        }
    }
}
Таким образом мы можем показать, что функция имеет доступ практически ко всему на том же уровне или выше. Это означает, что если бы мы добавили другую функцию с именем updateHighFiveCount внутри нашей функции giveHighFive, она бы имела доступ к своим родителям и объекту окна. Все, что будет делать эта новая функция, это увеличивать нашу переменную highFiveCoun до 5. Нам также нужно будет вызвать эту функцию, чтобы увеличить наше значение.
function giveHighFive()
{
    var highFiveCount = 0;
    function updateHighFiveCount()
    {
        highFiveCount += 5;
    }
    updateHighFiveCount();
    return highFiveCount;
}
Это всё очень хорошо, но это не поможет. Мы просто перемещаем код, чтобы выполнить добавление во вновь созданной функции. У нас есть два варианта, чтобы решить нашу проблему. Нам нужен способ инициализации переменной highFiveCount. Эта проблема может быть решена с помощью функции SELF-INVOKING (самовызывающаяся функция). Self-invoking-функция - это функция, которая вызывает себя или другими словами, выполняется сразу после ее определения. Вот например, если вы не знакомы с концепцией.
(function (){
   console.log("I just called myself. :-)");
})();
В этом случае наша self-invoking функция, инициализирует переменную highFiveCount. Переменная highFiveCount однажды вернет себя. Нам нужен способ для получения результата, который является самой функцией. Далее нам нужен способ вызова функции updateHighFiveCount вне ее родителя, функции giveHighFive. Замыкание было создано для решения этой конкретной проблемы. Мы будем использовать функциональное выражение, чтобы сложить все вместе. Если вы не знакомы с функциональным выражением, то это переменная, которой вы присваиваете функцию.
var displayGreeting = function(name){
    console.log("Greeting tiny humans. I AM " + name);
}
//call it like this
displayGreeting("Thor");
 
Итак, вот наше реализованное замыкание.
var giveHighFive = (function(){
    var highFiveCount = 0;
    function updateHighFiveCount(){
        highFiveCount += 5;
    }
    updateHighFiveCount();
    return highFiveCount;
})();
Окей, давайте я вам объясню, что только что произошло с нашим кодом. • Мы присваиваем функцию нашей переменной giveHighFive, которая вызывает себя используя функциональное выражение. • Наша функция Self-invoking будет запущена только один раз. Чтобы сделать функцию Self-invoking, просто добавьте () в конце ее определения. • Теперь giveHighFive имеет доступ к переменной highFiveCount. В двух словах, это и есть замыкание. Затем вы можете просто присвоить переменную giveHighFive нашему событию onclick кнопки и VOILA. Проблема решена. В общем-то, теперь вы имеете представление что такое замыкание и как его юзать. Если ты дочитал это до конца - ты красава😎