Буквенное обозначение объекта JavaScript в сравнении с обычными функциями и последствиями производительности?

Предположим, что у меня есть такие функции, как:

function foo() {

}

function bar() {

}

Я могу написать выше как обозначение Object Literal:

var Baz = {
  foo: function() {
  },
 bar: function() {
 }
};

Насколько я понимаю в последнем случае, экземпляр Baz будет создан, когда script загружается независимо от того, когда какая-либо функция Baz когда-либо вызывается. В первом случае объект функции создается только при вызове этой функции. Правильно ли я отношусь к этим предположениям?

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

Как вы относитесь к этому из своего профессионального опыта? Есть ли разница в скорости?

Ответы

Ответ 1

В первом случае объект функции создается только при вызове этой функции.

Нет, функции создаются независимо.

Обратите внимание, что вы также можете сделать это:

function foo() {
}

function bar() {
}

var Baz = {
  foo: foo,
  bar: bar
};

Или это:

var Baz = (function() {
    function foo() {
    }

    function bar() {
    }

    return {
      foo: foo,
      bar: bar
    };
})();

Основная цель размещения функций на Baz в качестве свойств - сделать их доступными как "методы" на Baz. Это может быть для удобства, для "пространства имен" и т.д. В вашей первой форме (и моей первой форме выше), если этот код находится в глобальной области видимости, foo и bar добавляются в глобальную область, которая может получить довольно многолюдно довольно быстро (особенно в браузерах). Во втором примере единственным глобальным символом является Baz, потому что функции анонимны. В моем последнем примере выше единственный глобальный символ Baz, но функции не анонимны, у них есть имена, которые могут показать вам отладчики и трассировки стека (что хорошо, подробнее здесь).

С точки зрения попытки оптимизации при создании функций, как это работает: когда выполнение входит в заданный контекст (глобальный контекст или контекст, связанный с вызовом функции), все это делается:

  • Создан контекстный объект выполнения за кадром.
  • Создается объект переменной за кадром для этого контекста выполнения.
  • В случае контекста функции:
    • Свойство добавляется к объекту переменной для arguments (массивная вещь, которую вы можете использовать для доступа к аргументам)
    • Свойство добавляется к объекту переменной для каждой из функций с именем arguments, со значением аргумента
    • Если функция имеет имя, ее имя добавляется как свойство объекта переменной и имеет значение объекта функции.
  • Свойства создаются в объекте переменной для каждой переменной, объявленной с помощью var в контексте выполнения; их значения первоначально undefined (независимо от того, имеет ли на нем var инициализатор).
  • Каждое объявление функции в контексте обрабатывается. (Функциональные выражения еще не обработаны, больше о различиях ниже). Свойство объекта переменной для каждого имени функции создается и получает объект функции как его значение.
  • Выполняется пошаговое выполнение кода.
    • Как и все выражения, выражения функций оцениваются, когда они встречаются в пошаговом потоке. Операторы
    • var, которые имеют инициализаторы (например, var a = 2;), обрабатываются точно так же, как и операторы присваивания (a = 2;); аспект var был сделан гораздо раньше. (var часто неправильно понимается. Например, у нас был этот вопрос вчера.)

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

Пример объявления функции:

function foo() {
}

Пример выражения функции:

var foo = function() {
};

Другой:

var Baz = {
    foo: function() { }
};

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

Пример выражения с именованной функцией:

var f = function foo() {  // <== Don't do this (more below)
};

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