A ordem das operações é mais clara quando você explora o operador vírgula dentro da notação de colchetes para ver quais partes são executadas quando:
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
Olhando para as especificações :
A produção AssignmentExpression : LeftHandSideExpression = AssignmentExpressioné avaliada da seguinte forma:
Seja lref o resultado da avaliação de LeftHandSideExpression.
Seja rref o resultado da avaliação de AssignmentExpression.
Deixe rval ser GetValue(rref).
Lança uma exceção SyntaxError se ... (irrelevante)
Ligue PutValue(lref, rval).
PutValueé o que lança o TypeError:
Deixe O ser ToObject(base).
Se o resultado da chamada do [[CanPut]]método interno de O com o argumento P for falso, então
uma. Se Throw for true, lance uma exceção TypeError.
Nada pode ser atribuído a uma propriedade de undefined- o [[CanPut]]método interno de undefinedsempre retornará false.
Em outras palavras: o intérprete analisa o lado esquerdo, a seguir analisa o lado direito e, a seguir , lança um erro se a propriedade do lado esquerdo não puder ser atribuída.
Quando você faz
a.x.y = b.e = 1
O lado esquerdo é analisado com sucesso até que PutValueseja chamado; o fato de a .xpropriedade ser avaliada como undefinednão é considerado até que o lado direito seja analisado. O intérprete vê isso como "Atribuir algum valor à propriedade" y "de undefined", e atribuir a uma propriedade undefinedapenas joga dentro PutValue.
Em contraste:
a.x.y.z = b.e = 1
O intérprete nunca chega ao ponto em que tenta atribuir à zpropriedade, porque primeiro deve resolver a.x.ypara um valor. Se a.x.yresolvido para um valor (mesmo para undefined), estaria tudo bem - um erro seria lançado dentro PutValuecomo acima. Mas o acesso a.x.y gera um erro, porque a propriedade ynão pode ser acessada em undefined.
b.z = 1eb.e = 1executaria primeiro (dada a associatividade à direita ativada=), depoisa.x.y.z = ...executaria e falharia; por que abatribuição é aprovada em um caso, mas não no outro?