Позвольте мне рассказать вам историю о кружке, рюмке, миндале и кешью. Допустим, у вас есть кружка с рюмкой в ​​ней:

Затем вы бросаете миндаль в кружку, и он падает в рюмку:

Когда вы наливаете кружку, получается рюмка с миндалем в ней:

Вы даже можете добавить еще орехов, если хотите:

Когда вы разливаете рюмку, у вас есть оба ореха, хотя миндаль изначально был брошен в кружку, а кешью - в рюмку:

Рюмка получила кешью в качестве аргумента и миндаль после закрытия.

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

Например, предположим, что у нас есть объект пользователя и список покемонов. Мы хотим отфильтровать список покемонов, чтобы мы возвращали только избранное пользователей:

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

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

Теперь функция onlyFavorites зависит от своего окружения; если мы переместим его в другой модуль, код сломается, если user также не определен там. Также сложнее протестировать, потому что функция имеет косвенный ввод. Нехорошо.

Замыкания снова приходят на помощь:

Мы можем передать user в onlyFavorites, позволить ему «упасть» во внутреннюю функцию, а затем вернуть эту функцию. Эта функция примет pokemon, который filter передает ей, и все равно запомнит user.

Функция onlyFavorites - это кружка.
Функция onlyUserFavorites - это рюмка.
user - это миндаль, который мы бросили в кружку, который упал в рюмку.
pokemon, через который проходит фильтр. это кешью.