¿Por qué esta línea es válida en javascript?
var a = 0[0];
Después de eso, aes undefined.
"0"de un new Number(0)objeto.
0[0]devolver un valor
0["toString"]Eso es genial, gracias por señalarlo.
¿Por qué esta línea es válida en javascript?
var a = 0[0];
Después de eso, aes undefined.
"0"de un new Number(0)objeto.
0[0]devolver un valor
0["toString"]Eso es genial, gracias por señalarlo.
Respuestas:
Cuando lo haga 0[0], el intérprete de JS convertirá el primero 0en un Numberobjeto y luego intentará acceder a la [0]propiedad de ese objeto que es undefined.
No hay ningún error de sintaxis porque la sintaxis de acceso a la propiedad 0[0]está permitida por la gramática del idioma en este contexto. Esta estructura (usando términos en la gramática de Javascript) es NumericLiteral[NumericLiteral].
La parte relevante de la gramática del lenguaje de la sección A.3 de la especificación ECMAScript de ES5 es la siguiente:
Literal ::
NullLiteral
BooleanLiteral
NumericLiteral
StringLiteral
RegularExpressionLiteral
PrimaryExpression :
this
Identifier
Literal
ArrayLiteral
ObjectLiteral
( Expression )
MemberExpression :
PrimaryExpression
FunctionExpression
MemberExpression [ Expression ]
MemberExpression . IdentifierName
new MemberExpression Arguments
Entonces, uno puede seguir la gramática a través de esta progresión:
MemberExpression [ Expression ]
PrimaryExpression [ Expression ]
Literal [ Expression ]
NumericLiteral [ Expression ]
Y, de manera similar, también Expressionpuede eventualmente ser NumericLiteralasí después de seguir la gramática, vemos que esto está permitido:
NumericLiteral [ NumericLiteral ]
Lo que significa que 0[0]es una parte permitida de la gramática y, por lo tanto, no SyntaxError.
Luego, en tiempo de ejecución, se le permite leer una propiedad que no existe (solo se leerá como undefined) siempre que la fuente de la que está leyendo sea un objeto o tenga una conversión implícita a un objeto. Y, de hecho, un literal numérico tiene una conversión implícita a un objeto (un objeto Number).
Esta es una de esas características a menudo desconocidas de Javascript. Los tipos Number, Booleany Stringen Javascript, generalmente se almacenan internamente como primitivas (no como objetos completos). Se trata de una representación de almacenamiento compacta e inmutable (probablemente hecha de esta manera para la eficiencia de la implementación). Pero, Javascript quiere que pueda tratar estas primitivas como objetos con propiedades y métodos. Por lo tanto, si intenta acceder a una propiedad o método que no es compatible directamente con la primitiva, JavaScript coaccionará temporalmente la primitiva en un tipo de objeto apropiado con el valor establecido en el valor de la primitiva.
Cuando usa una sintaxis similar a un objeto en una primitiva como 0[0], el intérprete lo reconoce como un acceso a la propiedad en una primitiva. Su respuesta a esto es tomar la primera 0primitiva numérica y convertirla en un Numberobjeto en toda regla en el que luego puede acceder a la [0]propiedad. En este caso específico, la [0]propiedad de un objeto Number es la undefinedrazón por la que ese es el valor que obtiene 0[0].
Aquí hay un artículo sobre la conversión automática de una primitiva en un objeto con el propósito de tratar con propiedades:
La vida secreta de los primitivos de JavaScript
Aquí están las partes relevantes de la especificación ECMAScript 5.1:
Lanza TypeError si el valor es undefinedo null, de lo contrario, devuelve true.

- Sea baseReference el resultado de evaluar MemberExpression.
- Deje que baseValue sea GetValue (baseReference).
- Sea propertyNameReference el resultado de evaluar Expression.
- Deje que propertyNameValue sea GetValue (propertyNameReference).
- Llame a CheckObjectCoercible (baseValue).
- Deje que propertyNameString sea ToString (propertyNameValue).
- Si la producción sintáctica que se está evaluando está contenida en el código de modo estricto, deje que estricto sea verdadero, de lo contrario, deje que estricto sea falso.
- Devuelve un valor de tipo Reference cuyo valor base es baseValue y cuyo nombre referenciado es propertyNameString, y cuyo indicador de modo estricto es estricto.
Una parte operativa de esta pregunta es el paso 5 anterior.
Esto describe cómo cuando el valor al que se accede es una referencia de propiedad, llama ToObject(base)para obtener la versión del objeto de cualquier primitiva.
Esto describe cómo Boolean, Numbery las Stringprimitivas se convierten en un formulario de objeto con la propiedad interna [[PrimitiveValue]] establecida en consecuencia.
Como prueba interesante, si el código fuera así:
var x = null;
var a = x[0];
Todavía no arrojaría un SyntaxError en el tiempo de análisis, ya que esta es una sintaxis técnicamente legal, pero arrojaría un TypeError en el tiempo de ejecución cuando ejecute el código porque cuando la lógica de Accessors de propiedad anterior se aplica al valor de x, llamará CheckObjectCoercible(x)o llamará a ToObject(x)cuál ambos arrojarán un TypeError si xes nullo undefined.
0[1,2]también es válido, ¿qué significa? (Actualizo la pregunta)
nullo undefinedesté totalmente bien, incluso si esas propiedades no existen.
0[2]
1,2pero devuelve 2.
Como la mayoría de los lenguajes de programación, JS usa una gramática para analizar su código y convertirlo en un formato ejecutable. Si no hay una regla en la gramática que se pueda aplicar a un fragmento particular de código, arroja un SyntaxError. De lo contrario, el código se considera válido, sin importar si tiene sentido o no.
Las partes relevantes de la gramática JS son
Literal ::
NumericLiteral
...
PrimaryExpression :
Literal
...
MemberExpression :
PrimaryExpression
MemberExpression [ Expression ]
...
Dado que 0[0]cumple con estas reglas, se considera una expresión válida . Si es correcto (por ejemplo, no arroja un error en tiempo de ejecución) es otra historia, pero sí lo es. Así es como JS evalúa expresiones como someLiteral[someExpression]:
someExpression(que puede ser complejo arbitrario)Number, cadenas => Stringetc.)get propertyoperación en el resultado (2) con el nombre de la propiedad resultado (1)Entonces 0[0]se interpreta como
index = 0
temp = Number(0)
result = getproperty(temp, index) // it's undefined, but JS doesn't care
delete temp
return result
A continuación, se muestra un ejemplo de una expresión válida , pero incorrecta :
null[0]
Se analiza bien, pero en tiempo de ejecución, el intérprete falla en el paso 2 (porque nullno se puede convertir en un objeto) y arroja un error de tiempo de ejecución.
var x = null; var a = x[0];no genera un error de sintaxis, pero arroja un TypeError en tiempo de ejecución.
0[0]a devolver un valor en lugar de indefinido
Hay situaciones en las que podría subíndice válidamente un número en Javascript:
-> 0['toString']
function toString() { [native code] }
Si bien no es evidente de inmediato por qué querría hacer esto, el subíndice en Javascript es equivalente a usar la notación con puntos (aunque la notación con puntos le limita a usar identificadores como claves).
(0).toString(sin llamar a la función). Es una propiedad del tipo de número.
0se acceda a su propiedad y como no existe, undefinedes más correcto como se explica en jfriend00.
0[0]devolverá undefined. Es probable que así sea, pero no tiene por qué ser así
Solo me gustaría señalar que esta sintaxis válida no es de ninguna manera exclusiva de Javascript. La mayoría de los lenguajes tendrán un error de tiempo de ejecución o un error de tipo, pero eso no es lo mismo que un error de sintaxis. Javascript elige devolver undefined en muchas situaciones en las que otro idioma podría generar una excepción, incluso cuando se subíndice un objeto que no tiene una propiedad del nombre de pila.
La sintaxis no conoce el tipo de expresión (incluso una expresión simple como un literal numérico) y le permitirá aplicar cualquier operador a cualquier expresión. Por ejemplo, intentar subíndice undefinedo nullprovoca un TypeErroren Javascript. No es un error de sintaxis; si esto nunca se ejecuta (estando en el lado equivocado de una sentencia if), no causará ningún problema, mientras que un error de sintaxis, por definición, siempre se detecta en tiempo de compilación (eval, Function, etc. , todos cuentan como compilación).
Porque es una sintaxis válida, e incluso un código válido para ser interpretado. Puede intentar acceder a cualquier propiedad de cualquier objeto (y en este caso 0 se convertirá en un objeto Número), y le dará el valor si existe, de lo contrario indefinido. Sin embargo, intentar acceder a una propiedad de undefined no funciona, por lo que 0 [0] [0] resultaría en un error de tiempo de ejecución. Sin embargo, esto todavía se clasificaría como sintaxis válida. Hay una diferencia entre lo que es una sintaxis válida y lo que no causará errores en tiempo de ejecución / tiempo de compilación.
No solo la sintaxis es válida, el resultado no tiene por qué serlo undefineden la mayoría de los casos, si no en todos los casos cuerdos. JS es uno de los lenguajes orientados a objetos más puros. La mayoría de los llamados lenguajes OO están orientados a clases, en el sentido de que no se puede cambiar la forma (está ligada a la clase) del objeto una vez creado, solo el estado del objeto. En JS puede cambiar el estado y la forma del objeto y esto lo hace con más frecuencia de lo que cree. Esta capacidad lo convierte en un código bastante oscuro, si lo usa incorrectamente. Los números son inmutables, por lo que no puede cambiar el objeto en sí, ni su estado ni su forma, por lo que podría hacerlo.
0[0] = 1;
que es una expresión de asignación válida que devuelve 1 pero en realidad no asigna nada, el número 0es inmutable. Lo que en sí mismo es algo extraño. Puede tener una expresión de asignación válida y correcta (ejecutable), que no asigna nada (*). Sin embargo, el tipo de numeral es un objeto mutable por lo que puede mutar el tipo, y los cambios caerán en cascada por la cadena del prototipo.
Number[0] = 1;
//print 1 to the console
console.log(0[0]);
//will also print 1 to the console because all integers have the same type
console.log(1[0]);
por supuesto, está muy lejos de la categoría de uso sano, pero el lenguaje está especificado para permitir esto porque en otros escenarios, extender las capacidades de los objetos tiene mucho sentido. Así es como los complementos de jQuery se enganchan en el objeto jQuery para dar un ejemplo.
(*) En realidad, asigna el valor 1 a la propiedad de un objeto, sin embargo, no hay forma de que pueda hacer referencia a ese objeto (transitorio) y, por lo tanto, se recopilará en el paso nexx GC
En JavaScript, todo es objeto, por lo que cuando el intérprete lo analiza, trata 0 como un objeto e intenta devolver 0 como una propiedad. Lo mismo sucede cuando intenta acceder al elemento 0 de verdadero o "" (cadena vacía).
Incluso si establece 0 [0] = 1, establecerá la propiedad y su valor en la memoria, pero mientras accede a 0 se trata como un número (no se confunda entre tratar como Objeto y número aquí).
true[0]o""[0]