2010-06-21 10 views
6

¿Puede explicar cómo la expresión de JavaScript:¿Cómo exactamente analiza la expresión de JavaScript [1 [{}]?

[1 [{}]] 

analiza/evalúa? En Firefox, Chrome, Konqueror y rhino, parece crear una matriz con un solo elemento, undefined. Sin embargo, no entiendo por qué.

En Firefox:

[1 [{}]].toSource() 

produce

[(void 0)] 

Sustitución 1 con otros valores que JavaScript para producir el mismo resultado.

Actualización: Creo que ahora entiendo. Codeka, Adrian y CMS aclararon cosas. En cuanto a la norma, traté de caminar a través de ECMAScript 5.

  1. 1 [{}] es una propiedad de acceso, por lo que está cubierto de §11.2.1.
  2. baseReference es el resultado de la evaluación de 1, por lo que todavía 1.
  3. baseValue = GetValue(baseReference) == 1.
  4. En GetValue (§8.7.1), Type(1) no es Reference (unión un nombre resuelto), de modo de vuelta 1.
  5. propertyNameReference es resultado de evaluar {}, por lo que un objeto vacío.
  6. propertyNameValue = GetValue(propertyNameReference) == {}
  7. En CheckObjectCoercible(baseValue) (§9.10), volvemos (Número es objeto coercible).
  8. propertyNameString = ToString(propertyNameValue)
  9. En ToString (§9.8), volver ToString(ToPrimitive({}, hint String))
  10. En ToPrimitive (§9.1), resultado retorno de objeto de [[DefaultValue]], pasando PreferredType (cadena).
  11. En [[DefaultValue]] (§8.12.8), deje que String sea el resultado de [[Get]] con el argumento toString.
  12. Esto se define en §15.2.4.2 para devolver "[object " + [[Class]] + "]", donde [[Class]] es "Objeto" para el prototipo de objeto predeterminado.
  13. Dado que hay un toString llamable, lo llamamos con el argumento this siendo {}.
  14. Devuelve un valor de tipo Reference, cuyo valor base es BaseValue (1) y cuyo nombre de referencia es propertyNameString ("[object Object]").

Luego, vamos a Array initializer (§11.1.4), y construimos una matriz de elemento único con el resultado.

+1

No estoy seguro de por qué esto sería válida JavaScript ... para que pueda obtener resultados impredecibles del motor * * tratando de manejarlo. ..me parece un estado normal –

+0

@Nick, también soy escéptico de que sea JS válido, y estoy dispuesto a aceptar la posibilidad de que sea simplemente un comportamiento indefinido. Sin embargo, el hecho de que los 4 motores (que tienen implementaciones separadas) lo analicen de la misma manera es al menos interesante. –

+1

@Matthew - La respuesta de Adrián es una muy buena explicación del comportamiento en esos 4 navegadores, pero aún no creo que '[object]' sea un accesorio válido ... así que todavía depende de cada motor ver cómo funciona manejaría este caso. Sin embargo, este es un caso marginal, y no puedo encontrar nada en la especificación 3.1 que diga cómo debe manejarse exactamente. –

Respuesta

7

Si lo rompemos un poco, verá:

var foo = 1; 
var bar = {}; 
var baz = foo[bar]; 

[baz]; 

creo que es válido JavaScript, pero no soy un experto ...

+0

Creo que lo tienes. Probablemente no vi esto porque es inusual usar un número como un objeto JavaScript, y el objeto vacío es una clave inusual. ¿Tiene alguna idea sobre la parte '[(void 0)]'? –

+2

@Matthew: Supongo que dado que '1 [{}]' no está definido, '(void 0)' es simplemente la forma "canónica" del intérprete para representar "indefinido". –

8

Es porque usted está tratando de obtener la propiedad {} del objeto 1 y luego colocarlo en una matriz. 1 no tiene la propiedad {}, entonces 1[{}] es undefined.

Si reemplaza el 1 con una matriz, verá cómo está funcionando. Con 1 como [5] y {} como 0, es [[5][0]].

Además, tenga en cuenta que obj['property'] es lo mismo que obj.property.

15

Al leer el OP and Nick comments, creo que puedo ampliar un poco más el Adrian's answer para hacerlo más claro.

Es JavaScript perfectamente válido.

JavaScript maneja los nombres de las propiedades de los objetos como cadenas, los objetos no pueden contener otros tipos u otros objetos como claves, son solo cadenas.

El soporte de notación property accessor (MemberExpression [ Expression ]) implícitamente convierte la expresión entre corchetes en una cadena, por lo que:

var obj = {}; 
obj[{}] = "foo"; 
alert(obj["[object Object]"]); // foo 

En el ejemplo anterior se puede ver que le asigno un valor a la propiedad {}, y {}.toString() (o {}+'') produce la cadena "[object Object] (a través de Object.prototype.toString).

La expresión 1 [{}] convierte implícitamente la 1 Number primitiva a un objeto (esto es hecho por el acceso de propiedad) y lookups una propiedad denominada "[object Object]" la búsqueda propiedad se hace sobre la Number.prototype y los Object.prototype objetos, por ejemplo:

1['toString'] === Number.prototype.toString; // true 

Finalmente, la expresión 1 [{}] está entre corchetes ([1 [{}]]), esto es en realidad un literal de Array.

En conclusión aquí es cómo el programa de análisis evalúa la expresión:

[1 [{}]]; 
// ^The accessor expression is evaluated and converted to string 

[1 ["[object Object]"]]; 
//^A property lookup is made on an Number object 
// trying to access a property named "[object Object]" 

[undefined]; 
// ^the property is obviously not found 

    [undefined]; 
//^  ^
// An array literal is created with an element `0` which its value is `undefined` 
Cuestiones relacionadas