Порядок операцій чіткіший, коли ви використовуєте оператор комами всередині позначень дужки, щоб побачити, які частини виконуються, коли:
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
присвоєння проходить в одному випадку, а не в іншому?