var a = {}
var b = {}
try{
a.x.y = b.e = 1 // Uncaught TypeError: Cannot set property 'y' of undefined
} catch(err) {
console.error(err);
}
console.log(b.e) // 1
var a = {}
var b = {}
try {
a.x.y.z = b.e = 1 // Uncaught TypeError: Cannot read property 'y' of undefined
} catch(err) {
console.error(err);
}
console.log(b.e) // undefined
答案 0 :(得分:150)
实际上,如果您正确阅读了错误消息,则情况1和情况2会引发不同的错误。
案例a.x.y
:
无法设置未定义的属性“ y”
案例a.x.y.z
:
无法读取未定义的属性“ y”
我想最好用简单的英语逐步执行来描述它。
案例1
// 1. Declare variable `a`
// 2. Define variable `a` as {}
var a = {}
// 1. Declare variable `b`
// 2. Define variable `b` as {}
var b = {}
try {
/**
* 1. Read `a`, gets {}
* 2. Read `a.x`, gets undefined
* 3. Read `b`, gets {}
* 4. Set `b.z` to 1, returns 1
* 5. Set `a.x.y` to return value of `b.z = 1`
* 6. Throws "Cannot **set** property 'y' of undefined"
*/
a.x.y = b.z = 1
} catch(e){
console.error(e.message)
} finally {
console.log(b.z)
}
案例2
// 1. Declare variable `a`
// 2. Define variable `a` as {}
var a = {}
// 1. Declare variable `b`
// 2. Define variable `b` as {}
var b = {}
try {
/**
* 1. Read `a`, gets {}
* 2. Read `a.x`, gets undefined
* 3. Read `a.x.y`, throws "Cannot **read** property 'y' of undefined".
*/
a.x.y.z = b.z = 1
} catch(e){
console.error(e.message)
} finally {
console.log(b.z)
}
在评论中,Solomon Tam找到了this ECMA documentation about assignment operation。
答案 1 :(得分:56)
当您在以下情况下利用括号符号内的逗号运算符查看要执行的部分时,操作顺序会更清楚:
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
看spec:
产品
AssignmentExpression : LeftHandSideExpression = AssignmentExpression
的评估如下:
让lref是评估LeftHandSideExpression的结果。
让rref成为评估AssignmentExpression的结果。
让rval为
GetValue(rref)
。如果...(无关),抛出SyntaxError异常
致电
PutValue(lref, rval)
。
PutValue
是引发TypeError
的原因:
让我们成为
ToObject(base)
。如果使用参数P调用O的
[[CanPut]]
内部方法的结果为false,则a。如果Throw为true,则抛出TypeError异常。
不能为undefined
的属性分配任何内容-[[CanPut]]
的{{1}}内部方法将始终返回undefined
。
换句话说:解释器先解析左侧,然后解析右侧,如果不能将左侧的属性分配给然后,则会引发错误
这样做的时候
false
成功解析了左侧 ,直到调用a.x.y = b.e = 1
为止;直到解析完右侧后,才考虑PutValue
属性的值为.x
的事实。解释器将其视为“为未定义的属性y分配一些值”,而分配给属性undefined
仅在undefined
内部抛出。
相反:
PutValue
解释器永远不会试图分配给a.x.y.z = b.e = 1
属性,因为它首先必须将z
解析为一个值。如果a.x.y
解析为一个值(甚至解析为a.x.y
),也可以-像上面一样在undefined
内抛出错误。但是访问 PutValue
会引发错误,因为无法在a.x.y
上访问属性y
。
答案 2 :(得分:3)