Порядок операцій чіткіший, коли ви використовуєте оператор комами всередині позначень дужки, щоб побачити, які частини виконуються, коли:
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
Дивлячись на специфікацію :
Виробництво AssignmentExpression : LeftHandSideExpression = AssignmentExpressionоцінюється так:
Нехай lref є результатом оцінки LeftHandSideExpression.
Нехай rref є результатом оцінки AssignmentExpression.
Нехай rval буде GetValue(rref).
Викиньте виняток SyntaxError, якщо ... (не має значення)
Дзвінок PutValue(lref, rval).
PutValueце те, що кидає TypeError:
Нехай О буде ToObject(base).
Якщо результат виклику [[CanPut]]внутрішнього методу O аргументом Р помилковим, то
а. Якщо Throw правда, то киньте виняток TypeError.
Нічого не можна присвоїти властивості undefined- [[CanPut]]внутрішній метод undefinedволі завжди повернеться false.
Іншими словами: інтерпретатор аналізує ліву частину, потім аналізує праву, а потім видає помилку, якщо властивість з лівої сторони не може бути призначена.
Коли ви робите
a.x.y = b.e = 1
Ліва частина успішно розібрана , поки не PutValueбуде викликана; той факт, що .xвластивість, що оцінюється undefined, не враховується до моменту розбору правої частини. Інтерпретатор розглядає це як "Присвоєння деякого значення властивості" y "невизначеного" та присвоєння властивості undefinedлише кидків всередину PutValue.
У контрасті:
a.x.y.z = b.e = 1
Інтерпретатор ніколи не доходить до того, коли він намагається призначити zвластивість, тому що спочатку він повинен вирішити a.x.yзначення. Якщо a.x.yвирішити значення (навіть до undefined), було б добре - помилка буде кинута всередину, PutValueяк вище. Але доступ a.x.y вказує на помилку, оскільки доступ до властивості yне можна отримати undefined.
b.z = 1іb.e = 1виконати спочатку (з урахуванням права асоціативності на=), а потімa.x.y.z = ...виконати і відмовити; чомуbприсвоєння проходить в одному випадку, а не в іншому?