Я изучаю THREE.js и заметил шаблон, в котором функции определены так:
var foo = ( function () {
var bar = new Bar();
return function ( ) {
//actual logic using bar from above.
//return result;
};
}());
(Пример смотрите здесь метод raycast ).
Нормальное изменение такого метода будет выглядеть следующим образом :
var foo = function () {
var bar = new Bar();
//actual logic.
//return result;
};
Сравнивая первую версию с обычным вариантом, кажется, что первая отличается тем:
- Он присваивает результат самоисполняющейся функции.
- Он определяет локальную переменную внутри этой функции.
- Он возвращает фактическую функцию, содержащую логику, которая использует локальную переменную.
Таким образом, основное отличие состоит в том, что в первом варианте полоса назначается только один раз при инициализации, а во втором варианте эта временная переменная создается каждый раз при вызове.
Мое лучшее предположение о том, почему это используется, заключается в том, что он ограничивает количество экземпляров для bar (будет только один) и, таким образом, экономит накладные расходы на управление памятью.
Мои вопросы:
- Верно ли это предположение?
- Есть ли название у этого паттерна?
- Почему это используется?
javascript
closures
iife
Патрик Клуг
источник
источник
Ответы:
Ваши предположения почти верны. Давайте сначала рассмотрим их.
Это называется выражением функции с немедленным вызовом или IIFE.
Это способ иметь закрытые поля объекта в JavaScript, поскольку он не предоставляет
private
ключевое слово или функциональность иным образом.Опять же, главное, что эта локальная переменная является частной .
AFAIK вы можете назвать этот шаблон модульным шаблоном . Цитата:
Сравнивая эти два примера, я могу догадаться, почему используется первый:
Но если вам каждый раз нужен просто ванильный объект, то этот шаблон, вероятно, не принесет никакой пользы.
источник
Это ограничивает затраты на инициализацию объекта и дополнительно гарантирует, что все вызовы функций используют один и тот же объект. Это позволяет, например, сохранять состояние в объекте для использования в будущих вызовах.
Хотя возможно, что он ограничивает использование памяти, обычно сборщик мусора все равно будет собирать неиспользуемые объекты, поэтому этот шаблон вряд ли сильно поможет.
Этот узор представляет собой особую форму закрытия .
источник
Я не уверен, что у этого шаблона более правильное имя, но для меня это похоже на модуль, и причина, по которой он используется, заключается в том, чтобы как инкапсулировать, так и поддерживать состояние.
Замыкание (идентифицируемое функцией внутри функции) гарантирует, что внутренняя функция имеет доступ к переменным внутри внешней функции.
В приведенном вами примере внутренняя функция возвращается (и назначается ей
foo
) путем выполнения внешней функции, что означает, что онаtmpObject
продолжает существовать в пределах замыкания, и несколько вызовов внутренней функцииfoo()
будут работать с одним и тем же экземпляромtmpObject
.источник
Ключевое различие между вашим кодом и кодом Three.js заключается в том, что в коде Three.js переменная
tmpObject
инициализируется только один раз, а затем используется при каждом вызове возвращаемой функции.Это было бы полезно для сохранения некоторого состояния между вызовами, подобно тому, как
static
переменные используются в C-подобных языках.tmpObject
закрытая переменная, видимая только внутренней функции.Он изменяет использование памяти, но не предназначен для экономии памяти.
источник
Я хотел бы внести свой вклад в этот интересный поток, расширив концепцию шаблона раскрывающего модуля, который гарантирует, что все методы и переменные остаются закрытыми до тех пор, пока они не будут явно представлены.
В последнем случае метод сложения будет называться Calculator.add ();
источник
В приведенном примере первый фрагмент будет использовать один и тот же экземпляр tmpObject для каждого вызова функции foo (), где, как и во втором фрагменте, tmpObject будет каждый раз новым экземпляром.
Одна из причин, по которой мог быть использован первый фрагмент, заключается в том, что переменная tmpObject может использоваться совместно с вызовами foo () без утечки ее значения в область, в которой объявлен foo ().
Не сразу выполняемая версия функции первого фрагмента на самом деле будет выглядеть так:
Однако обратите внимание, что в этой версии tmpObject находится в той же области видимости, что и foo (), поэтому им можно будет управлять позже.
Лучшим способом достижения той же функциональности было бы использование отдельного модуля:
Модуль 'foo.js':
Модуль 2:
Сравнение производительности IEF и именованной функции создателя foo: http://jsperf.com/ief-vs- named-function
источник