Порядок операций более понятен, когда вы используете оператор запятой внутри скобки, чтобы увидеть, какие части выполняются, когда:
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
:
Пусть O будет ToObject(base)
.
Если результатом вызова внутреннего метода O [[CanPut]]
с аргументом P является false, то
a.Если Throw имеет значение true, тогда выдается исключение TypeError.
Ничто не может быть назначено свойству undefined
- внутренний метод [[CanPut]]
undefined
всегда будетreturn 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
.