이러한 JavaScript 코드 조각이 둘 다 오류가 발생하더라도 다르게 작동하는 이유는 무엇입니까?
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
실제로 오류 메시지를 제대로 읽으면 사례 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 은 할당 작업에 대한이 ECMA 문서를 찾았습니다 .
다음과 같은 경우 실행되는 부분을 확인하기 위해 대괄호 표기법 내부의 쉼표 연산자를 이용하면 작업 순서가 더 명확 해집니다.
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
은 다음과 같이 평가됩니다.
Let lref be the result of evaluating LeftHandSideExpression.
Let rref be the result of evaluating AssignmentExpression.
Let rval be
GetValue(rref)
.Throw a SyntaxError exception if... (irrelevant)
Call
PutValue(lref, rval)
.
PutValue
is what throws the TypeError
:
Let O be
ToObject(base)
.If the result of calling the
[[CanPut]]
internal method of O with argument P is false, thena. If Throw is true, then throw a TypeError exception.
Nothing can be assigned to a property of undefined
- the [[CanPut]]
internal method of undefined
will always return false
.
In other words: the interpreter parses the left-hand side, then parses the right-hand side, then throws an error if the property on the left-hand side can't be assigned to.
When you do
a.x.y = b.e = 1
The left hand side is successfully parsed up until PutValue
is called; the fact that the .x
property evaluates to undefined
is not considered until after the right-hand side is parsed. The interpreter sees it as "Assign some value to the property "y" of undefined", and assigning to a property of undefined
only throws inside PutValue
.
In contrast:
a.x.y.z = b.e = 1
The interpreter never gets to the point where it tries to assign to the z
property, because it first must resolve a.x.y
to a value. If a.x.y
resolved to a value (even to undefined
), it would be OK - an error would be thrown inside PutValue
like above. But accessing a.x.y
throws an error, because property y
cannot be accessed on undefined
.
Consider the following code:
var a = {};
a.x.y = console.log("evaluating right hand side"), 1;
The rough outline of steps required to execute the code is as follows ref:
- Evaluate the left hand side. Two things to keep in mind:
- Evaluate the right hand side.
- Get the value of result obtained in step 2.
- Set the value of the reference obtained in step 1 to the value obtained in step 3 i.e. set property
y
of undefined to the value. This is supposed to throw a TypeError exception ref.
'Programming' 카테고리의 다른 글
값이 JavaScript 또는 jQuery의 숫자인지 확인 (0) | 2020.08.09 |
---|---|
제목 표시 줄에 전체 디렉토리 경로를 표시하도록 OS X에서 Sublime Text 구성 (0) | 2020.08.09 |
Arraylist에서 Array로 (0) | 2020.08.08 |
CardView 배경색은 항상 흰색입니다. (0) | 2020.08.08 |
새 툴바의 제목 색상은 어떻게 설정합니까? (0) | 2020.08.08 |