Kolejność operacji jest jaśniejsza, gdy używasz operatora przecinka w notacji nawiasów, aby zobaczyć, które części są wykonywane, gdy:
var a = {}
var b = {}
try{
// Uncaught TypeError: Cannot set property 'y' of undefined
a
[console.log('x'), 'x']
[console.log('y'), 'y']
= (console.log('right hand side'), b.e = 1);
} catch(err) {
console.error(err);
}
console.log(b.e) // 1
var a = {}
var b = {}
try {
// Uncaught TypeError: Cannot read property 'y' of undefined
a
[console.log('x'), 'x']
[console.log('y'), 'y']
[console.log('z'), 'z']
= (console.log('right hand side'), b.e = 1);
} catch(err) {
console.error(err);
}
console.log(b.e) // undefined
Patrząc na specyfikację :
Produkcja AssignmentExpression : LeftHandSideExpression = AssignmentExpressionjest oceniana w następujący sposób:
Niech lref będzie wynikiem obliczania LeftHandSideExpression.
Niech rref będzie wynikiem obliczania AssignmentExpression.
Niech rval będzie GetValue(rref).
Rzuć wyjątek SyntaxError, jeśli ... (nieistotne)
Zadzwoń PutValue(lref, rval).
PutValueco rzuca TypeError:
Niech O będzie ToObject(base).
Jeśli wynik wywołania [[CanPut]]wewnętrznej metody O z argumentem P jest fałszywy, to
za. Jeśli Throw ma wartość true, zgłoś wyjątek TypeError.
Nic nie może być przypisane do właściwości undefined- [[CanPut]]wewnętrzna metoda undefinedzawsze zwraca false.
Innymi słowy: tłumacz analizuje lewą stronę, a następnie prawą stronę, a następnie zgłasza błąd, jeśli nie można przypisać właściwości po lewej stronie.
Kiedy to zrobisz
a.x.y = b.e = 1
Lewa strona jest pomyślnie analizowana do momentu PutValuewywołania; fakt, że .xwłaściwość jest oceniana jako, undefinedjest brany pod uwagę dopiero po przeanalizowaniu prawej strony. Interpreter widzi to jako „Przypisz jakąś wartość do właściwości„ y ”z undefined”, a przypisanie do właściwości undefinedtylko wrzuca do środka PutValue.
W przeciwieństwie:
a.x.y.z = b.e = 1
Interpreter nigdy nie dochodzi do punktu, w którym próbuje przypisać zwłaściwość, ponieważ najpierw musi rozstrzygnąć a.x.ywartość. Jeśli zostanie a.x.yrozstrzygnięty na wartość (nawet do undefined), byłoby OK - błąd zostałby wrzucony do środka, PutValuejak powyżej. Jednak dostęp do obiektu a.x.y generuje błąd, ponieważ ynie można uzyskać dostępu do właściwości undefined.
b.z = 1ib.e = 1najpierw wykonałbym (biorąc pod uwagę prawostronne skojarzenie=), a następniea.x.y.z = ...wykonałby i zawiódł; dlaczegobprzypisanie mija w jednym przypadku, a nie w drugim?