Более подробно о предыдущих ответах ...
С точки зрения общих компиляторов и без учета специфичных для ВМ оптимизаций:
Сначала мы проходим через фазу лексического анализа, где мы токенизируем код.
Например, могут быть получены следующие токены:
[]: 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 обычно не различают токен IDENTIFIER и токены для «нативных глобальных объектов». Следовательно...
Мы должны искать цепочку областей действия каждый раз, когда встречаем токен IDENTIFIER. Виртуальные машины Javascript содержат «объект активации» для каждого контекста выполнения, который может содержать объект «аргументы», локально определенные переменные и т. Д. Если мы не можем найти его в объекте активации, мы начинаем искать цепочку областей действия, пока не достигнем глобальной области видимости. , Если ничего не найдено, мы бросаем ReferenceError
.
Как только мы нашли объявление переменной, мы вызываем конструктор. new Array
является неявным вызовом функции, и практическое правило заключается в том, что вызовы функций медленнее во время выполнения (следовательно, почему статические компиляторы C / C ++ допускают «встраивание функций» - какие механизмы JS JIT, такие как SpiderMonkey, должны выполнять «на лету»)
Array
Конструктор перегружен. Конструктор Array реализован в виде нативного кода, поэтому он обеспечивает некоторые улучшения производительности, но ему все равно необходимо проверить длину аргументов и действовать соответствующим образом. Более того, если указан только один аргумент, нам необходимо дополнительно проверить тип аргумента. new Array ("foo") создает ["foo"], где new Array (1) создает [undefined]
Итак, чтобы упростить все это: с литералами массива, VM знает, что мы хотим массив; с new Array
, виртуальная машина должна использовать дополнительные циклы процессора, чтобы выяснить, что на new Array
самом деле делает.