May 7, 2020

Замыкания

Сегодня речь пойдет о замыканиях в JavaScript. Для многих эта тема подсознательно воспринимается непонятной и от того сложной. Но, в действительности, в замыканиях нет ничего страшного и сложного.

Что же такое замыкание? Если говорить простыми словами, то это просто функция в функции. Вот и все. Да-да. Так вот просто. Это функция, которая находится внутри другой функции.

Начнем сразу же с примеров, т.к. на них будет разобраться намного проще.

function hi() {
    return function() {
        console.log('Привет');
    }
}

Такая вот незамысловатая конструкция: у нас имеется функция hi, которая возвращает другую функцию.

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

hi(); // в консоль ничего не выведется

Так как функция hi возвращает новую функцию, то нам нужно ее вызвать, перед эти, для наглядности запишем ее в константу и вызовем ее:

const sayHi = hi();

sayHi(); // выведет в консоль слово "Привет"

Только после этой манипуляции мы сможем визуально увидеть результат.

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

Давай разбираться зачем это нужно.

В нашу функцию hi добавим параметр(аргумент), в который будем записывать имя человека, а в функции, которая сейчас выводит нам слово Привет в консоль добавим это имя. В итоге получим такой код:

function hi(name) {
    return function() {
        console.log(`Привет, ${name}`);
    }
}

Теперь заставим все это работать:

const sayHi = hi('Вася');
sayHi(); // выведет в консоль: Привет, Вася

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

Поправим немного код, для большего понимания:

const sayHiVasya = hi('Вася');
const sayHiPetya = hi('Петя');
sayHiVasya(); // выведет в консоль: Привет, Вася
sayHiPetya(); // выведет в консоль: Привет, Петя

Как видишь, мы передаем имена только в нашу функцию hi, и эти имена замыкаются в возвращаемых функциях.

Создание ссылок для соц. сетей

Может быть еще не совсем понятно, поэтому давай сделаем более близкий к практике пример использующий замыкания.

Давай сделаем с тобой некий генератор ссылок для социальных сетей.

function createSocLink(socialNetwork) {
    return function(nickname) {
        return `https://${socialNetwork}/${nickname}`;
    }
}

Итак, сначала разберем все в этом генераторе, а потом разберемся как им пользоваться.

В функцию createSocLink мы передаем параметр socialNetwork, который должен представлять из себя ссылку на какую-либо социальную сеть, т.е. должен иметь вид, к примеру:

  • vk.com
  • instagram.com
  • facebook.com

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

Итак, пробуем все это запустить.

Так как функция createSocLink вернет нам новую функцию, то запишем ее в константу:

const createVkLink = createSocLink('vk.com');

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

const createVkLink = createSocLink('vk.com');

console.log(createVkLink('durov'));
// в консоль выведется: https://vk.com/durov

Как видишь, мы создали ссылку на страницу создателя Вконтакте Павла Дурова.

Теперь давай создадим ссылки с помощью генератора на другие соц. сети и ты увидишь, в чем прелесть замыканий:

const createVkLink = createSocLink('vk.com');
const createInstagramLink = createSocLink('instagram.com');
const createFacebookLink = createSocLink('facebook.com');

Мы получили 3 новых функции:

  • createVkLink – создаем ссылки на страницы пользователей в Вконтакте;
  • createInstagramLink – создает ссылки на страницы пользователей в Instagram;
  • createFacebookLink – создает ссылки на страницы пользователей в Facebook.

Попробуем их в работе:

console.log(createVkLink('durov'));
console.log(createVkLink('admin'));
console.log(createVkLink('vasya'));
console.log('*****');
console.log(createInstagramLink('durov'));
console.log(createInstagramLink('admin'));
console.log(createInstagramLink('vasya'));
console.log('*****');
console.log(createFacebookLink('durov'));
console.log(createFacebookLink('admin'));
console.log(createFacebookLink('vasya'));

Получаем результат:

Ссылки прекрасно сгенерировались. Благодаря замыканию, мы получили список из 3ех генераторов ссылок:

const createVkLink = createSocLink('vk.com');
const createInstagramLink = createSocLink('instagram.com');
const createFacebookLink = createSocLink('facebook.com');

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

Домашнее задание

Создать функцию calc используя замыкания, которую можно использовать так:

const plus = calc(10);
plus(5); // должно вывести значение 15
plus(45); // должно вывести значение 55