Ampliando aún más las respuestas anteriores ...
Desde una perspectiva general de compiladores y sin tener en cuenta las optimizaciones específicas de VM:
Primero, pasamos por la fase de análisis léxico donde tokenizamos el código.
A modo de ejemplo, se pueden producir los siguientes tokens:
[]: 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)
Esperemos que esto le proporcione una visualización suficiente para que pueda comprender cuánto se requiere más (o menos) procesamiento.
Según los tokens anteriores, sabemos que ARRAY_INIT siempre producirá una matriz. Por lo tanto, simplemente creamos una matriz y la completamos. En cuanto a la ambigüedad, la etapa de análisis léxico ya ha distinguido ARRAY_INIT de un descriptor de acceso de propiedad de objeto (por ejemplo obj[foo]
) o corchetes dentro de cadenas / literales de expresiones regulares (por ejemplo, "foo [] bar" o / [] /)
Esto es minúsculo, pero también tenemos más tokens con new Array
. Además, todavía no está del todo claro que simplemente queremos crear una matriz. Vemos el token "nuevo", pero ¿"nuevo" qué? Luego vemos el token IDENTIFICADOR que significa que queremos un nuevo "Array", pero las máquinas virtuales de JavaScript generalmente no distinguen un token IDENTIFICADOR y tokens para "objetos globales nativos". Por lo tanto...
Tenemos que buscar la cadena de alcance cada vez que nos encontramos con un token IDENTIFICADOR. Las máquinas virtuales de Javascript contienen un "objeto de activación" para cada contexto de ejecución que puede contener el objeto "argumentos", variables definidas localmente, etc. Si no podemos encontrarlo en el objeto de activación, comenzamos a buscar la cadena de alcance hasta llegar al alcance global . Si no se encuentra nada, lanzamos un ReferenceError
.
Una vez que hemos localizado la declaración de variable, invocamos al constructor. new Array
es una llamada de función implícita, y la regla general es que las llamadas de función son más lentas durante la ejecución (de ahí que los compiladores estáticos de C / C ++ permitan la "función en línea", que los motores JS JIT como SpiderMonkey tienen que hacer sobre la marcha)
El Array
constructor está sobrecargado. El constructor de Array se implementa como código nativo, por lo que proporciona algunas mejoras de rendimiento, pero aún necesita verificar la longitud de los argumentos y actuar en consecuencia. Además, en el caso de que solo se proporcione un argumento, necesitamos verificar más a fondo el tipo del argumento. new Array ("foo") produce ["foo"] donde como new Array (1) produce [undefined]
Para simplificarlo todo: con los literales de matriz, la VM sabe que queremos una matriz; con new Array
, la VM necesita usar ciclos de CPU adicionales para descubrir qué hace new Array
realmente .