¿Por qué esta línea es válida en javascript?
var a = 0[0];
Después de eso, a
es undefined
.
javascript
Michael M.
fuente
fuente
true[0]
o""[0]
"0"
de unnew Number(0)
objeto.0[0]
devolver un valor0["toString"]
Eso es genial, gracias por señalarlo.Respuestas:
Cuando lo haga
0[0]
, el intérprete de JS convertirá el primero0
en unNumber
objeto y luego intentará acceder a la[0]
propiedad de ese objeto que esundefined
.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) esNumericLiteral[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:
Entonces, uno puede seguir la gramática a través de esta progresión:
Y, de manera similar, también
Expression
puede eventualmente serNumericLiteral
así después de seguir la gramática, vemos que esto está permitido: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
,Boolean
yString
en 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 primera0
primitiva numérica y convertirla en unNumber
objeto 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 laundefined
razón por la que ese es el valor que obtiene0[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:
9.10 CheckObjectCoercible
Lanza TypeError si el valor es
undefined
onull
, de lo contrario, devuelvetrue
.11.2.1 Acceso a la propiedad
Una parte operativa de esta pregunta es el paso 5 anterior.
8.7.1 Obtener valor (V)
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.9.9 ToObject
Esto describe cómo
Boolean
,Number
y lasString
primitivas se convierten en un formulario de objeto con la propiedad interna [[PrimitiveValue]] establecida en consecuencia.Como prueba interesante, si el código fuera así:
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á aToObject(x)
cuál ambos arrojarán un TypeError six
esnull
oundefined
.fuente
0[1,2]
también es válido, ¿qué significa? (Actualizo la pregunta)null
oundefined
esté totalmente bien, incluso si esas propiedades no existen.0[2]
1,2
pero 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
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 comosomeLiteral[someExpression]
:someExpression
(que puede ser complejo arbitrario)Number
, cadenas =>String
etc.)get property
operación en el resultado (2) con el nombre de la propiedad resultado (1)Entonces
0[0]
se interpreta comoA continuación, se muestra un ejemplo de una expresión válida , pero incorrecta :
Se analiza bien, pero en tiempo de ejecución, el intérprete falla en el paso 2 (porque
null
no se puede convertir en un objeto) y arroja un error de tiempo de ejecución.fuente
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 indefinidoHay situaciones en las que podría subíndice válidamente un número en Javascript:
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).
fuente
(0).toString
(sin llamar a la función). Es una propiedad del tipo de número.0
se acceda a su propiedad y como no existe,undefined
es 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
undefined
onull
provoca unTypeError
en 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).fuente
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.
fuente
No solo la sintaxis es válida, el resultado no tiene por qué serlo
undefined
en 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.que es una expresión de asignación válida que devuelve 1 pero en realidad no asigna nada, el número
0
es 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.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
fuente
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í).
fuente