当您利用括号符号内的逗号运算符来查看在以下情况下执行哪些部分时,操作顺序会更加清晰:
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)
。
如果[[CanPut]]
使用参数 P 调用 O 的内部方法的结果为 false,则
一种。如果 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
。