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 = AssignmentExpression
se 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)
.
PutValue
es 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 undefined
siempre 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 PutValue
se llama; el hecho de que la .x
propiedad se evalúe undefined
no 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 undefined
solo 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 z
propiedad, porque primero debe resolver a.x.y
a un valor. Si se a.x.y
resuelve en un valor (incluso a undefined
), estaría bien: se arrojaría un error dentro PutValue
como arriba. Pero acceder a.x.y
arroja un error, porque y
no se puede acceder a la propiedad en undefined
.
b.z = 1
yb.e = 1
ejecutaría primero (dada la asociatividad derecha activada=
), luegoa.x.y.z = ...
ejecutaría y fallaría; ¿Por qué lab
asignación pasa en un caso pero no en el otro?