2010-06-21 7 views
6

Czy możesz wyjaśnić, jak wyrażenie JavaScript:Jak dokładnie analizowane jest wyrażenie JavaScript [1 [{}]]?

[1 [{}]] 

analizuje/ocenia? W przeglądarkach Firefox, Chrome, Konqueror i rhino wydaje się tworzyć tablicę z jednym elementem, undefined. Jednak nie rozumiem dlaczego.

Firefox:

[1 [{}]].toSource() 

produkuje

[(void 0)] 

zastępując 1 z innymi wartościami JavaScript wydaje uzyskując ten sam wynik.

Aktualizacja: Myślę, że teraz rozumiem. Codeka, Adrian i CMS wyjaśniły rzeczy. Jeśli chodzi o normy, starałem się iść przez ECMAScript 5.

  1. 1 [{}] jest właściwością Accessor, więc jest pokryta §11.2.1.
  2. baseReference jest wynikiem oceny 1, więc nadal 1.
  3. baseValue = GetValue(baseReference) == 1.
  4. Na GetValue (§8.7.1) Type(1) nie Reference (zdecydowanym nazwa wiązania), a więc powrót 1.
  5. propertyNameReference jest wynikiem oceny {}, tak więc pusty obiektu.
  6. propertyNameValue = GetValue(propertyNameReference) == {}
  7. Na CheckObjectCoercible(baseValue) (§9.10), zwracamy (Liczba jest obiektowo-uboczna).
  8. propertyNameString = ToString(propertyNameValue)
  9. Na ToString (§9.8), powrót ToString(ToPrimitive({}, hint String))
  10. Na ToPrimitive (§9.1), wynik powrotnej obiektu [[DefaultValue]], przechodząc PreferredType (string).
  11. Przy [[DefaultValue]] (§8.12.8), niech toString będzie wynikiem [[Get]] z argumentem toString.
  12. To jest zdefiniowane w §15.2.4.2, aby zwrócić "[object " + [[Class]] + "]", gdzie [[Class]] jest "Obiektem" dla domyślnego prototypu obiektu.
  13. Ponieważ istnieje wywoływalny toString, nazywamy go argumentem this będącym {}.
  14. Zwraca wartość typu Reference, której podstawową wartością jest BaseValue (1) i której nazwa podana to propertyNameString ("[object Object]").

Następnie przechodzimy do inicjatora Array (§11.1.4) i tworzymy tablicę pojedynczych elementów z wynikiem.

+1

Nie jestem pewien, dlaczego miałoby to być ważne JavaScript ... więc masz nieprzewidywalne rezultaty silnika * * próbuje go obsłużyć. Stan ... jest normalny dla mnie. –

+0

@Nick, jestem także sceptyczny, że to jest prawidłowy JS i jestem skłonny zaakceptować możliwość, że jest to po prostu nieokreślone zachowanie. Jednak fakt, że wszystkie 4 silniki (które mają osobne implementacje) parsuje ją w ten sam sposób, jest co najmniej interesujący. –

+1

@Matthew - odpowiedź Adriana jest całkiem dobrym wyjaśnieniem zachowania w tych 4 przeglądarkach, nadal nie uważam, że '[obiekt]' jest prawidłowym akcesorium ... więc nadal będzie to zależało od każdego silnika poradziłbym sobie z tą sprawą. Jest to jednak poważny przypadek i nie mogę znaleźć niczego w specyfikacji 3.1, która mówi, jak należy dokładnie to zrobić. –

Odpowiedz

7

Jeśli łamiemy go trochę, zobaczysz:

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

[baz]; 

wierzę, że to ważne JavaScript, ale nie jestem ekspertem ...

+0

Myślę, że to masz. Prawdopodobnie nie widziałem tego, ponieważ nietypowe jest używanie liczby jako obiektu JavaScript, a pusty obiekt to nietypowy klucz. Czy masz jakieś przemyślenia na temat '[(void 0)]'? –

+2

@Matthew: Domyślam się, że ponieważ '1 [{}]' jest niezdefiniowane, '(void 0)' jest po prostu "kanoniczną" formą interpretatora dla reprezentowania "undefined". –

8

To dlatego, że próbujesz uzyskać obiekt {} obiektu, a następnie umieść go w tablicy. 1 nie ma właściwości {}, więc 1[{}] jest undefined.

Jeśli zastąpisz 1 tablicą, zobaczysz, jak działa. Z 1 jako [5] i {} jako 0, jest to [[5][0]].

Należy również pamiętać, że obj['property'] jest tożsamy ​​z obj.property.

15

Czytanie OP and Nick comments, myślę, że mogę rozszerzyć nieco bardziej Adrian's answer, aby uczynić go jaśniejszym.

To jest całkowicie poprawny JavaScript.

JavaScript obsługuje nazwy właściwości obiektów jako ciągi, obiekty nie mogą zawierać innych typów ani innych obiektów, jak klucze, są to tylko ciągi.

Wspornik notacja property accessor (MemberExpression [ Expression ]) niejawnie konwertuje wyrażenie w nawiasach w ciąg tak:

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

W powyższym przykładzie widać, że przypisanie wartości do właściwości {} i {}.toString() (lub {}+'') produkuje ciąg "[object Object] (przez Object.prototype.toString).

Wyrażenie 1 [{}] niejawnie konwertuje 1 Number prymitywny do obiektu (jest to dokonywane przez akcesor nieruchomości) i Lookups właściwość o nazwie "[object Object]" odnośnika nieruchomość składa się na Number.prototype i Object.prototype obiektów, na przykład:

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

Wreszcie, wyrażenie 1 [{}] jest samo w nawiasach ([1 [{}]]), jest to właściwie literał tablicowy.

Podsumowując oto jak parser oblicza wyrażenie:

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