Ответ 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
.