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 = AssignmentExpression
jest 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)
.
PutValue
co 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 undefined
zawsze 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 PutValue
wywołania; fakt, że .x
właściwość jest oceniana jako, undefined
jest 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 undefined
tylko 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ć z
właściwość, ponieważ najpierw musi rozstrzygnąć a.x.y
wartość. Jeśli zostanie a.x.y
rozstrzygnięty na wartość (nawet do undefined
), byłoby OK - błąd zostałby wrzucony do środka, PutValue
jak powyżej. Jednak dostęp do obiektu a.x.y
generuje błąd, ponieważ y
nie można uzyskać dostępu do właściwości undefined
.
b.z = 1
ib.e = 1
najpierw wykonałbym (biorąc pod uwagę prawostronne skojarzenie=
), a następniea.x.y.z = ...
wykonałby i zawiódł; dlaczegob
przypisanie mija w jednym przypadku, a nie w drugim?