Почему arr = [] быстрее, чем arr = новый массив?

Я запустил этот код и получил следующий результат. Мне интересно узнать, почему [] быстрее?

console.time('using[]')
for(var i=0; i<200000; i++){var arr = []};
console.timeEnd('using[]')

console.time('using new')
for(var i=0; i<200000; i++){var arr = new Array};
console.timeEnd('using new')
  • с помощью []: 299ms
  • с помощью new: 363мс

Благодаря Raynos здесь представлен эталонный код этого кода, а некоторые более возможный способ определения переменной.

enter image description here

Ответ 1

Дальнейшее расширение предыдущих ответов...

С точки зрения общих компиляторов и без учета специфических для VM оптимизаций:

Во-первых, мы проходим фазу лексического анализа, в которой мы кодируем код.

В качестве примера могут быть созданы следующие токены:

[]: ARRAY_INIT
[1]: ARRAY_INIT (NUMBER)
[1, foo]: ARRAY_INIT (NUMBER, IDENTIFIER)
new Array: NEW, IDENTIFIER
new Array(): NEW, IDENTIFIER, CALL
new Array(5): NEW, IDENTIFIER, CALL (NUMBER)
new Array(5,4): NEW, IDENTIFIER, CALL (NUMBER, NUMBER)
new Array(5, foo): NEW, IDENTIFIER, CALL (NUMBER, IDENTIFIER)

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

  • Основываясь на вышеупомянутых токенах, мы знаем, что ARRAY_INIT всегда будет создавать массив. Поэтому мы просто создаем массив и заполняем его. Что касается двусмысленности, то на этапе лексического анализа уже был выделен ARRAY_INIT из объекта доступа объекта (например, obj[foo]) или скобки внутри строк/регулярных выражений (например, "foo [] bar" или /[]/)

  • Это немного, но у нас также больше токенов с new Array. Кроме того, пока не совсем ясно, что мы просто хотим создать массив. Мы видим "новый" токен, но "новый", что? Затем мы видим токен IDENTIFIER, который означает, что мы хотим создать новый "массив", но JavaScript VM вообще не различает токен IDENTIFIER и токены для "родных глобальных объектов". Поэтому...

  • Мы должны искать цепочку областей видимости каждый раз, когда мы сталкиваемся с токеном IDENTIFIER. Javascript VM содержат "объект активации" для каждого контекста выполнения, который может содержать объект "аргументы", локально определенные переменные и т.д. Если мы не сможем найти его в объекте Activation, мы начнем искать цепочку областей действия до тех пор, пока не достигнем глобальной области, Если ничего не найдено, мы бросаем ReferenceError.

  • Как только мы найдем объявление переменной, мы вызываем конструктор. new Array - это вызов неявной функции, и эмпирическое правило состоит в том, что вызовы функций медленнее во время выполнения (следовательно, почему статические компиляторы C/С++ допускают "встраивание функций" - какие JS-движки JIT, такие как SpiderMonkey, должны делать on- летать)

  • Конструктор Array перегружен. Конструктор Array реализуется как собственный код, поэтому он обеспечивает некоторые улучшения производительности, но по-прежнему необходимо проверить длину аргументов и действовать соответственно. Более того, в случае, когда предоставляется только один аргумент, нам нужно дополнительно проверить тип аргумента. new Array ( "foo" ) создает [ "foo" ], где, когда новый массив (1) создает [ undefined]

Итак, чтобы упростить все это: с помощью литералов массива, VM знает, что нам нужен массив; с помощью new Array виртуальная машина должна использовать дополнительные циклы CPU, чтобы выяснить, что на самом деле делает new Array.

Ответ 2

Одна из возможных причин состоит в том, что new Array требует поиска имени на Array (у вас может быть переменная с этим именем в области), а [] - нет.

Ответ 3

Хороший вопрос. Первый пример называется литералом массива. Это предпочтительный способ создания массивов среди многих разработчиков. Возможно, разница в производительности вызвана проверкой аргументов нового вызова Array(), а затем созданием объекта, тогда как литерал создает массив напрямую.

Относительно небольшая разница в производительности поддерживает этот момент, я думаю. Например, вы можете сделать тот же тест с литералом Object и object {}.

Ответ 4

Это будет иметь смысл

Литералы объектов позволяют нам писать код, который поддерживает множество функции все еще делают его относительно простым для исполнителей нашего кода. Нет необходимости ссылаться на конструкторы напрямую или поддерживать правильный порядок аргументов, передаваемых функциям и т.д.

http://www.dyn-web.com/tutorials/obj_lit.php