Позвольте мне рассказать вам историю о кружке, рюмке, миндале и кешью. Допустим, у вас есть кружка с рюмкой в ней:
Затем вы бросаете миндаль в кружку, и он падает в рюмку:
Когда вы наливаете кружку, получается рюмка с миндалем в ней:
Вы даже можете добавить еще орехов, если хотите:
Когда вы разливаете рюмку, у вас есть оба ореха, хотя миндаль изначально был брошен в кружку, а кешью - в рюмку:
Рюмка получила кешью в качестве аргумента и миндаль после закрытия.
Замыкание - это когда внутренняя область видимости использует что-то из внешней области. Внутренняя область видимости «запоминает» свою внешнюю область видимости, когда она определена, и может использовать любые переменные из этой области.
Например, предположим, что у нас есть объект пользователя и список покемонов. Мы хотим отфильтровать список покемонов, чтобы мы возвращали только избранное пользователей:
Мы можем использовать user
во внутренней области, даже если она была определена во внешней области, потому что внутренние области получают доступ к внешним областям через замыкание.
Теперь предположим, что мы хотим провести рефакторинг этого кода, чтобы извлечь анонимную функцию, передаваемую фильтру:
Теперь функция onlyFavorites
зависит от своего окружения; если мы переместим его в другой модуль, код сломается, если user
также не определен там. Также сложнее протестировать, потому что функция имеет косвенный ввод. Нехорошо.
Замыкания снова приходят на помощь:
Мы можем передать user
в onlyFavorites
, позволить ему «упасть» во внутреннюю функцию, а затем вернуть эту функцию. Эта функция примет pokemon
, который filter
передает ей, и все равно запомнит user
.
Функция onlyFavorites
- это кружка.
Функция onlyUserFavorites
- это рюмка. user
- это миндаль, который мы бросили в кружку, который упал в рюмку. pokemon
, через который проходит фильтр. это кешью.