Подальше розгортання попередніх відповідей ...
З точки зору загальної компіляції та зневаги до оптимізацій, характерних для 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. VM Javascript містять "об’єкт активації" для кожного контексту виконання, який може містити об'єкт "аргументи", локально визначені змінні тощо. Якщо ми не можемо знайти його в об'єкті активації, ми починаємо шукати ланцюг області, поки не досягнемо глобальної області застосування . Якщо нічого не знайдемо, ми кидаємо а ReferenceError
.
Після того як ми знайшли декларацію змінної, ми викликаємо конструктор. new Array
- це неявний виклик функції, і правило роботи полягає в тому, що виклики функцій є повільнішими під час виконання (отже, чому статичні компілятори C / C ++ дозволяють "функцію вбудовування" - що JS JIT-двигуни, такі як SpiderMonkey, повинні робити на ходу)
Array
Конструктор перевантажений. Конструктор Array реалізований як нативний код, тому він забезпечує деякі покращення продуктивності, але йому все одно потрібно перевірити довжину аргументів і діяти відповідно. Більше того, якщо наводиться лише один аргумент, нам потрібно додатково перевірити тип аргументу. новий масив ("foo") виробляє ["foo"], де як новий масив (1) виробляє [undefined]
Отже, щоб спростити все це: з літералами масиву VM знає, що ми хочемо масив; з new Array
, VM потрібно використовувати додаткові цикли процесора, щоб зрозуміти, що new Array
насправді робить.