Потребляет ли создание функций больше памяти


// Case A
function Constructor() {
  this.foo = function() {
    ...
  };
  ...
}

// vs 
// Case B
function Constructor() {
  ...
};

Constructor.prototype.foo = function() {
  ...
}
Одна из главных причин, по которой люди советуют использовать прототипы, заключается в том, что .foo создается один раз в случае прототипа, где as this.foo создается несколько раз при использовании другого подхода.

Однако можно было бы ожидать, что интерпретаторы могут оптимизировать это. Так что существует только одна копия функции foo в случае A.

Конечно, вы все равно будете иметь уникальный контекст области для каждого объекта из-за замыканий, но это имеет меньше накладных расходов, чем новая функция для каждого объекта. объект.

Оптимизируют ли современные интерпретаторы JS случай A таким образом, что существует только одна копия функции foo ?

3 7

3 ответа:

Да, создание функций требует больше памяти.

... и нет, интерпретаторы не оптимизируют регистр A до одной функции.

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

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

Update: Только что запустил этот тест, который создает 1M "экземпляров" конструктора, используя узел.js (то есть V8, интерпретатор JS в Chrome). С помощью caseA = true я получаю следующее использование памяти:

{ rss: 212291584,
vsize: 3279040512,
heapTotal: 203424416,
heapUsed: 180715856 }

И с caseA = false я получаю это использование памяти:

{ rss: 73535488,
vsize: 3149352960,
heapTotal: 74908960,
heapUsed: 56308008 }

Таким образом, функции замыкания определенно потребляя значительно больше памяти, почти в 3 раза, но в абсолютном смысле мы говорим только о разнице ~140-150 байт на экземпляр. (Однако это, скорее всего, увеличится в зависимости от количества переменных в области действия, которые будут у вас при создании функции).

Я полагаю, после некоторого краткого тестирования в узле, что в обоих случаях A и B существует только одна копия фактического кода для функции foo в памяти.

Случай A-существует объект функции, созданный для каждого выполнения Constructor(), хранящий ссылку на код функции и ее текущую область выполнения.

Случай B - существует только одна область видимости, один объект функции, совместно используемый через прототип.

Интерпретаторы javascript также не оптимизируют объекты-прототипы. Это просто случай, когда существует только один из них на тип (ссылка на несколько экземпляров). Конструкторы, с другой стороны, создают новые экземпляры и методы, определенные в них. Таким образом, по определению, это действительно не вопрос "оптимизации" интерпретатора, а просто понимания того, что происходит.

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