Как называется этот шаблон JavaScript и почему он используется?


Я учусь три.js и заметил шаблон, где функции определяются следующим образом:

var foo = ( function () {
    var bar = new Bar();

    return function ( ) {
        //actual logic using bar from above.
        //return result;
    };
}());

(пример см. Метод raycast здесь).

The нормальный вариация такого метода будет выглядеть так:

var foo = function () {
    var bar = new Bar();

    //actual logic.
    //return result;
};

сравнение первой версии до нормальный вариация, первый, кажется, отличается тем, что:

  1. он присваивает результат самостоятельного выполнения функция.
  2. он определяет локальную переменную в этой функции.
  3. возвращает фактический функция, содержащая логику, которая использует локальную переменную.

мое лучшее предположение о том, почему это используется, что ограничивает количество экземпляры для bar (будет только один) и, таким образом, экономит накладные расходы на управление памятью.

мои вопросы:

  1. правильно ли это предположение?
  2. есть ли название для этого шаблона?
  3. почему это?
6 101

6 ответов:

ваши предположения почти верны. Давайте сначала рассмотрим их.

  1. он назначает возврат самоисполняющейся функции

Это называется сразу-вызывается функция выражения или IIFE

  1. он определяет локальную переменную в этой функции

Это способ иметь частные поля объектов в JavaScript, как это делает не предоставлять private ключевое слово или функциональность в противном случае.

  1. он возвращает фактическую функцию, содержащую логику, которая использует локальную переменную.

опять же, главное, что эта локальная переменная частная.

есть ли имя для этого шаблона?

AFAIK вы можете назвать этот шаблон Модуль Pattern. Цитирование:

в Шаблон модуля инкапсулирует "конфиденциальность", состояние и организацию с помощью замыканий. Он обеспечивает способ обертывания смеси публичных и частных методов и переменных, защищая части от утечки в глобальную область и случайного столкновения с интерфейсом другого разработчика. С помощью этого шаблона возвращается только общедоступный API, сохраняя все остальное в закрытии закрытым.

сравнивая эти два примера, мои лучшие догадки о том, почему первый используется являются:

  1. он реализует шаблон Одноэлементного дизайна.
  2. можно управлять способом создания объекта определенного типа с помощью первого примера. Один близкий матч с этой точкой может быть статические методы фабрики как описано в эффективной Java.
  3. Это эффективное если вам нужно одно и то же состояние объекта каждый раз.

но если вам просто нужен объект ванили каждый раз, то этот шаблон будет вероятно, не добавит никакой ценности.

Это ограничивает затраты на инициализацию объекта и дополнительно гарантирует, что все вызовы функций используют то же самое

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

закрытие (определенная функция внутри функции) гарантирует, что внутренняя функция имеет доступ к переменным внутри внешней функции.

в приведенном примере внутренняя функция возвращается (и присваивается foo), выполнив внешнюю функцию, которая означает tmpObject продолжается чтобы жить в закрытии и несколько вызовов внутренней функции foo() будет работать на том же экземпляре tmpObject.

ключевое различие между вашим кодом и тремя.JS код, что в три.JS-код переменной tmpObject инициализируется только один раз, а затем совместно используется каждым вызовом возвращаемой функции.

Это было бы полезно для сохранения некоторого состояния между вызовами, аналогично тому, как static переменные используются в C-подобных языках.

tmpObject является частной переменной, видимой только для внутренней функции.

Он изменяет использование памяти, но его не предназначен экономить память.

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

enter image description here

в последнем случае метод сложения будет называться калькулятором.добавить();

В приведенном примере первый фрагмент будет использовать один и тот же экземпляр tmpObject для каждого вызова функции foo(), где, как и во втором фрагменте, tmpObject будет каждый раз новым экземпляром.

одна из причин, по которой первый фрагмент может быть использован, заключается в том, что переменная tmpObject может быть разделена между вызовами foo (), без утечки ее значения в область, в которой объявлен foo ().

не сразу выполняемая версия функции первого фрагмент на самом деле будет выглядеть так:

var tmpObject = new Bar();

function foo(){
    // Use tmpObject.
}

однако обратите внимание, что эта версия имеет tmpObject в той же области, что и foo (), поэтому ею можно будет управлять позже.

лучшим способом достижения той же функциональности было бы использовать отдельный модуль:

модуль ' foo.js':

var tmpObject = new Bar();

module.exports = function foo(){
    // Use tmpObject.
};

Модуль 2:

var foo = require('./foo');

сравнение производительности IEF и именованной функции foo creator: http://jsperf.com/ief-vs-named-function