El orden de las operaciones es más claro cuando explota el operador de coma dentro de la notación de corchetes para ver qué partes se ejecutan cuando:
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
Mirando la especificación :
La producción AssignmentExpression : LeftHandSideExpression = AssignmentExpressionse evalúa de la siguiente manera:
Sea lref el resultado de evaluar LeftHandSideExpression.
Sea rref el resultado de evaluar AssignmentExpression.
Sea rval GetValue(rref).
Lanzar una excepción SyntaxError si ... (irrelevante)
Llame PutValue(lref, rval).
PutValuees lo que arroja el TypeError:
Sea O ToObject(base).
Si el resultado de llamar al [[CanPut]]método interno de O con el argumento P es falso, entonces
a. Si Throw es verdadero, entonces lanza una excepción TypeError.
No se puede asignar nada a una propiedad de undefined: el [[CanPut]]método interno de undefinedsiempre volverá false.
En otras palabras: el intérprete analiza el lado izquierdo, luego analiza el lado derecho, luego arroja un error si no se puede asignar la propiedad del lado izquierdo.
Cuando tu lo hagas
a.x.y = b.e = 1
El lado izquierdo se analiza con éxito hasta que PutValuese llama; el hecho de que la .xpropiedad se evalúe undefinedno se considera hasta que se analiza el lado derecho. El intérprete lo ve como "Asignar algún valor a la propiedad" y "de indefinido", y asignarlo a una propiedad de undefinedsolo arroja dentroPutValue .
A diferencia de:
a.x.y.z = b.e = 1
El intérprete nunca llega al punto en el que intenta asignar a la zpropiedad, porque primero debe resolver a.x.ya un valor. Si se a.x.yresuelve en un valor (incluso a undefined), estaría bien: se arrojaría un error dentro PutValuecomo arriba. Pero acceder a.x.y arroja un error, porque yno se puede acceder a la propiedad en undefined.
b.z = 1yb.e = 1ejecutaría primero (dada la asociatividad derecha activada=), luegoa.x.y.z = ...ejecutaría y fallaría; ¿Por qué labasignación pasa en un caso pero no en el otro?