2010-06-21 13 views
6

può spiegare come l'espressione JavaScript:Come esattamente l'espressione JavaScript [1 [{}]] analizza?

[1 [{}]] 

analizza/Esamina? In Firefox, Chrome, Konqueror e Rhino, sembra che crei un array con un singolo elemento, undefined. Tuttavia, non capisco perché.

In Firefox:

[1 [{}]].toSource() 

produce

[(void 0)] 

Sostituzione 1 con altri valori JavaScript sembra produrre lo stesso risultato.

Aggiornamento: Penso di aver capito ora. codeka, Adrian e CMS hanno chiarito le cose. Per quanto riguarda la serie, ho provato a camminare attraverso ECMAScript 5.

  1. 1 [{}] è una funzione di accesso di proprietà, quindi è coperto in §11.2.1.
  2. baseReference è il risultato della valutazione 1, quindi ancora 1.
  3. baseValue = GetValue(baseReference) == 1.
  4. A GetValue (§8.7.1), Type(1) non è Reference (associazione di un nome risolto), quindi ritorno 1.
  5. propertyNameReference è risultato della valutazione {}, quindi un oggetto vuoto.
  6. propertyNameValue = GetValue(propertyNameReference) == {}
  7. A CheckObjectCoercible(baseValue) (§9.10), si ritorna (il numero è coercibile con l'oggetto).
  8. propertyNameString = ToString(propertyNameValue)
  9. A ToString (§9.8), restituire ToString(ToPrimitive({}, hint String))
  10. A ToPrimitive (§9.1), return risultato dell'oggetto di [[DefaultValue]], passando PreferredType (stringa).
  11. A [[DefaultValue]] (§8.12.8), lasciare toString essere risultato di [[Get]] con argomento toString.
  12. Questo è definito in §15.2.4.2 per restituire "[object " + [[Class]] + "]", dove [[Class]] è "Oggetto" per il prototipo dell'oggetto predefinito.
  13. Poiché è disponibile un numero chiamante toString, viene chiamato con l'argomento this{}.
  14. Restituisce un valore di tipo Reference, il cui valore di base è BaseValue (1) e il cui nome di riferimento è propertyNameString ("[object Object]").

Quindi passiamo all'inizializzatore di array (§11.1.4) e costruiamo un array di elementi singolo con il risultato.

+1

Io non sono sicuro perché questo sarebbe valido JavaScript ... in modo da ottenere risultati imprevedibili del motore * * cercando di gestirlo. ... mi sembra normale. –

+0

@Nick, sono anche scettico sul fatto che sia valido JS e sono disposto ad accettare la possibilità che sia semplicemente un comportamento indefinito. Tuttavia, il fatto che tutti e 4 i motori (che hanno implementazioni separate) la analizzano allo stesso modo è almeno interessante. –

+1

@Matthew - La risposta di Adrian è una buona spiegazione del comportamento in quei 4 browser, non penso ancora che '[object]' sia un accessor valido ... quindi sarebbe ancora su ogni engine su come gestire questo caso. Questo è un caso limite, e non riesco a trovare nulla nella specifica 3.1 che dice come dovrebbe essere gestito esattamente. –

risposta

7

Se rompiamo in su un po ', vedrete:

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

[baz]; 

Credo che sia valida JavaScript, ma io non sono un esperto ...

+0

Penso che tu ce l'abbia. Probabilmente non l'ho visto perché è insolito usare un numero come oggetto JavaScript, e l'oggetto vuoto è una chiave insolita. Hai qualche idea sulla parte '[(void 0)]'? –

+2

@Matthew: La mia ipotesi è che dato che '1 [{}]' non è definito, '(void 0)' è semplicemente la forma "canonica" dell'interprete per rappresentare "indefinito". –

8

È perché si sta cercando di ottenere la proprietà {} dell'oggetto 1 e quindi posizionarlo in un array. 1 non ha la proprietà {}, quindi 1[{}] è undefined.

Se si sostituisce lo 1 con un array, si vedrà come funziona. Con 1 come [5] e {} come 0, è [[5][0]].

Inoltre, tenere presente che obj['property'] corrisponde a obj.property.

15

Leggendo il OP and Nick comments, penso di poter espandere un po 'di più lo Adrian's answer per renderlo più chiaro.

È JavaScript perfettamente valido.

JavaScript gestisce nomi di proprietà oggetto come stringhe, gli oggetti non possono contenere altri tipi o altri oggetti come chiavi, sono solo stringhe.

La staffa notazione property accessor (MemberExpression [ Expression ]) converte implicitamente l'espressione fra parentesi in una stringa, quindi:

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

Nell'esempio di cui sopra si può vedere che io assegno un valore alla proprietà {}, e {}.toString() (oppure {}+'') produce la stringa "[object Object] (via Object.prototype.toString).

L'espressione 1 [{}] converte implicitamente l'1 Number primitivo a un oggetto (ciò è reso dalla funzione di accesso proprietà) e ricerche una proprietà denominata "[object Object]" la ricerca struttura avviene sulle ei Object.prototype oggetti Number.prototype, ad esempio:

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

Infine, l'espressione 1 [{}] è racchiuso in parentesi ([1 [{}]]), questo è in realtà un array letterale.

In conclusione ecco come il parser valuta l'espressione:

[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` 
Problemi correlati