Какие подводные камни есть у замыканий?

C замыканиями я знаком, знаю как их применить.

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

Пример с setTimeout показывать не надо. Как они работают я понимаю.

Я гуглил, был на https://javascript.info/ и https://developer.mozilla.org/. Не нашел ответа.

Решил посетить этот источник.

Хотелось бы с примером где есть недостаток.

Или ссылку на источник, буду благодарен.


Ответы (1 шт):

Автор решения: Sergei Kirjanov

С замыканиями то всё хорошо, а вот люди несовершенны...

Вот хотел человек каждую секунду по числу, а получил 5 пятерок сразу:

for(var i=0;i<5;i++) {
    setTimeout(()=>console.log(i), 1000)
    console.log('privet')
}
  1. Если замыкание передается аргументом в какую-то функцию (здесь setTimeout), то эта функция и определяет, когда и сколько раз будет запущено замыкание. setTimeout вызвался в цикле 5 раз подряд почти одновременно. Каждый вызов закидывал замыкание в будущее на 1 секунду. Все console.log('privet') сработали на секунду раньше всех console.log(i).
  2. var говорит о том, что переменная определена для окружающей функции, в цикле она меняется. Из замыкания будет видно текущее значение переменной. Т. к. все console.log(i) выполнятся после цикла, они увидят i на момент окончания цикла (когда i перестало подходить под условие).
  3. если var заменить на let, то у каждой итерации цикла (и у каждого из 5-и созданных замыканий) будет своя i, и console.log(i) напечатает числа от 0 до 4.

Еще this вечно чему попало равен в function(){...

В function(){ this не замыкается. В this попадает объект, который стоял до . при вызове функции: iWillBeThisInside.fun(), a если вызывалось просто fun(), то глобальный объект (часто window).

Возможно, это было настолько частой ошибкой, что при введении стрелочных функций (=>) сделали по-другому. Здесь this внутри будет такой же, как снаружи, при создании замыкания.

И всё бы хорошо, но определения методов классов ведут себя, как просто function. Так что, мучаемся ... используем .bind(this) дальше.


Из объективных недостатков: У замыканий есть накладные расходы на создание и запуск. По сути, при создании замыкания создается объект. Например, while работает быстрее forEach. Эти накладные расходы могут иметь значение при оптимизации тяжелых вычислений, или хранении в памяти большого количества объектов-замыканий. Для обычного кода разница не будет заметна, и преждевременной оптимизации лучше избегать, отдавая предпочтение ясности (надежности) кода.

→ Ссылка