window.onload = function() {
   var a = function(x) {
       console.log(x);
   };
   document.onclick = function() {
       a(1);
   };
   document.onkeyup = function() {
       a(2);
   };
};

Я прекрасно понимаю, почему это работает, но не как.

Когда window.onload заканчивается , a уничтожается, но функция, на которую он ссылается, по-прежнему доступна для обработчиков событий, поскольку она была объявлена в более высоком контексте, если я правильно понимаю ,

Сохраняет ли интерпретатор скрытую ссылку на функцию в фоновом режиме или интерпретатор каким-то образом встроил функцию? Этот тип кода, чтобы избежать глобальной переменной, эффективен? Спасибо.

4
user479870 4 Фев 2013 в 11:41

6 ответов

Лучший ответ

Сохраняет ли интерпретатор скрытую ссылку на функцию в фоновом режиме или интерпретатор каким-то образом встроил функцию?

На это нельзя ответить глобально для всех движков JavaScript. Но синтаксическому анализатору, скорее всего, придется хранить ссылку на вашу функцию a для обеих анонимных функций, которые вы определяете в document.onclick и document.onkeyup. Так что a не уничтожается сразу, он недоступен только из-за ограничений области видимости переменной javascript.

Вот почему замыкания могут привести к утечкам памяти, потому что движку трудно действительно разыменовать a должным образом. (которая была проблемой с IE Engine и до сих пор, когда не обрабатывается тщательно). А поскольку вы не можете разыменовать a вручную, поскольку у вас нет доступа к переменной, нет быстрых исправлений утечек памяти, возникающих из этого типа шаблона.

Ваш пример также не является закрытием, поскольку не возвращает функцию, но она имеет дело с теми же проблемами с областью видимости переменных, поскольку она ссылается на локальную переменную a внутри функций, не разделяющих ту же область видимости (document.onclick и document.onkeyup).

Я очень подозреваю, что ни один движок не будет пытаться встроить функцию a, так как это излишне дублирует объект функции. Скорее всего, он хранится с pointer и указанным количеством ссылок можно легко уничтожить, когда счетчик ссылок уменьшится до 0 (в вашем примере, когда document.onclick и document.onkeyup разыменовываются (установите null или undefined).

Эффективен ли этот тип кода для избежания глобальной переменной?

Всегда хорошо избегать глобальных переменных, поэтому в общем случае: да, это эффективный способ избежать глобальных переменных. Каждый хороший движок также должен уничтожать a после разыменования document.onclick и document.onkeyup.

0
Community 23 Май 2017 в 10:27

Это известно как «Закрытие». Короче говоря, это означает, что «функция имеет доступ ко всем переменным в области, в которой она определена».

В вашем примере два обработчика определены внутри функции window.onload, поэтому она может обращаться к a, что также входит в эту область.

И да, переводчик хранит все замыкания в памяти. ( AFAIK )
Я не профессиональный программист, поэтому у меня мало полномочий. Но я обычно делаю это, чтобы избежать глобалов.

Закрытие на MDN

0
TwiNight 4 Фев 2013 в 08:13

Область видимости или контекстный объект автоматически создаются JavaScript в тот момент, когда вы объявляете первую функцию внутри обработчика window.onload; этот объект области видимости сохраняет переменную a, что делает ее эксклюзивной для обеих ваших анонимных функций.

Этот метод часто используется для сокрытия информации и предотвращения создания глобальных переменных. После выполнения кода onload ни один другой код не имеет доступа к a.

0
Ja͢ck 4 Фев 2013 в 08:43

Функции или ссылки на них в переменной в javascript являются типом объектов и, подобно обычным объектам, функциям или переменным, содержащим ссылки на них, не занимаются сборкой мусора, пока на них нет ссылок. В вашем конкретном случае вы создали пару ссылок на a(), которые длятся дольше, чем обработчик .onload(). Таким образом, переменная a длится намного дольше, чем функция тоже. Эта концепция известна как «закрытие».

Если вы ищете в Google термин «замыкания в javascript», вы найдете много полезных статей по этой теме, таких как этот.

0
jfriend00 4 Фев 2013 в 08:11

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

Язык на самом деле не имеет понятия области видимости блока (хотя он действительно обладает областью действия). Объекты автоматически очищаются фоновым GC, только когда не осталось ссылок. Таким образом, поведение вашего объекта a является своего рода «безопасным»: одна ссылка отбрасывается, когда заканчивается область действия функции, а другая остается.

Более подробный ответ должен был бы тщательно исследовать реализацию конкретного движка Javascript, вероятно, до детали, большей, чем у нас есть время или пространство для этого.

0
Lightness Races in Orbit 4 Фев 2013 в 08:09

Когда window.onload заканчивается, a уничтожается ...

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

Рекомендуемое чтение: http://www.ibm.com/developerworks/web/library / ва - memleak /

1
user123444555621 4 Фев 2013 в 08:17