이 줄이 자바 스크립트에서 유효한 이유는 무엇입니까?
var a = 0[0];
그 후, a
이다 undefined
.
답변
당신이 할 때 0[0]
하면 JS 인터프리터는 첫 번째 0
를 Number
객체 로 변환 한 다음 [0]
해당 객체 의 속성에 액세스하려고합니다 undefined
.
0[0]
이 컨텍스트의 언어 문법에서 속성 액세스 구문 을 허용 하므로 구문 오류가 없습니다 . 이 구조 (Javascript 문법의 용어 사용)는 NumericLiteral[NumericLiteral]
.
언어 문법의 관련 부분 ES5 ECMAScript 사양의 섹션 A.3 은 다음과 같습니다.
Literal ::
NullLiteral
BooleanLiteral
NumericLiteral
StringLiteral
RegularExpressionLiteral
PrimaryExpression :
this
Identifier
Literal
ArrayLiteral
ObjectLiteral
( Expression )
MemberExpression :
PrimaryExpression
FunctionExpression
MemberExpression [ Expression ]
MemberExpression . IdentifierName
new MemberExpression Arguments
따라서이 진행 과정을 통해 문법을 따를 수 있습니다.
MemberExpression [ Expression ]
PrimaryExpression [ Expression ]
Literal [ Expression ]
NumericLiteral [ Expression ]
그리고 비슷하게 Expression
NumericLiteral
문법을 따른 후에도 결국 그렇게 될 수 있습니다 .
NumericLiteral [ NumericLiteral ]
이는 0[0]
문법의 허용 된 부분이므로 SyntaxError가 없음을 의미합니다 .
그런 다음 런타임에 읽고있는 undefined
소스가 객체이거나 객체에 대한 암시 적 변환이있는 한 존재하지 않는 속성을 읽을 수 있습니다 (단지로 읽음 ). 그리고 숫자 리터럴은 실제로 객체 (Number 객체)로 암시 적으로 변환됩니다.
이것은 자바 스크립트의 알려지지 않은 기능 중 하나입니다. 유형 Number
, Boolean
및String
자바 스크립트는 일반적으로 프리미티브 (안 완전한 객체)로 내부적으로 저장됩니다. 이것은 컴팩트하고 변경 불가능한 스토리지 표현입니다 (아마도 구현 효율성을 위해이 방식으로 수행됨). 그러나 Javascript는 이러한 기본 요소를 속성 및 메서드가있는 객체처럼 처리 할 수 있기를 바랍니다. 따라서 프리미티브에서 직접 지원되지 않는 속성이나 메서드에 액세스하려고하면 Javascript는 값이 프리미티브의 값으로 설정된 적절한 유형의 객체로 프리미티브를 일시적으로 강제합니다.
와 같은 기본 요소에서 객체와 유사한 구문을 사용하면 0[0]
인터프리터는이를 기본 요소에 대한 속성 액세스로 인식합니다. 이에 대한 응답은 첫 번째 0
숫자 프리미티브 를 가져 와서 속성에 Number
액세스 할 수 있는 완전한 객체 로 강제 변환하는 것 [0]
입니다. 이 특정 경우 [0]
에는 Number 객체 의 속성 undefined
이에서 얻은 값입니다 0[0]
.
다음은 속성을 처리하기 위해 기본 요소를 객체로 자동 변환하는 방법에 대한 기사입니다.
다음은 ECMAScript 5.1 사양의 관련 부분입니다.
값이 undefined
또는 이면 TypeError를 던지고 null
, 그렇지 않으면를 반환합니다 true
.
- baseReference를 MemberExpression을 평가 한 결과로 둡니다.
- baseValue를 GetValue (baseReference)로 둡니다.
- propertyNameReference를 Expression 평가의 결과로 둡니다.
- propertyNameValue를 GetValue (propertyNameReference)로 둡니다.
- CheckObjectCoercible (baseValue)를 호출합니다.
- propertyNameString을 ToString (propertyNameValue)로 둡니다.
- 평가되는 구문 생성이 Strict 모드 코드에 포함되어 있으면 strict를 true로, 그렇지 않으면 strict를 false로 둡니다.
- 기본 값이 baseValue이고 참조 된 이름이 propertyNameString이고 엄격 모드 플래그가 엄격한 Reference 유형의 값을 반환합니다.
이 질문에 대한 작동 부분은 위의 5 단계입니다.
액세스되는 값이 속성 참조 일 때 ToObject(base)
모든 기본 요소의 객체 버전을 가져 오기 위해 호출하는 방법을 설명합니다 .
이는 Boolean
, Number
및 String
프리미티브가 [[PrimitiveValue]] 내부 속성이 적절히 설정된 객체 형태로 변환되는 방법을 설명합니다 .
흥미로운 테스트로, 코드가 다음과 같으면 :
var x = null;
var a = x[0];
이 기술적으로 법적 구문으로 아직 구문 분석시에 구문 에러가 발생하지 것입니다,하지만 당신은 코드를 실행하면 속성 접근 자 로직 위의이 값에 적용될 때 때문에 런타임에서 형식 오류를 던질 것 x
, 그것은 호출 CheckObjectCoercible(x)
또는 호출 ToObject(x)
하는 경우 모두 형식 오류가 발생합니다 x
입니다 null
나 undefined
.
답변
대부분의 프로그래밍 언어와 마찬가지로 JS는 문법을 사용하여 코드를 구문 분석하고 실행 가능한 형식으로 변환합니다. 특정 코드 청크에 적용 할 수있는 문법 규칙이 없으면 SyntaxError가 발생합니다. 그렇지 않으면 코드가 의미가 있는지 여부에 관계없이 유효한 것으로 간주됩니다.
JS 문법 의 관련 부분은 다음 과 같습니다.
Literal ::
NumericLiteral
...
PrimaryExpression :
Literal
...
MemberExpression :
PrimaryExpression
MemberExpression [ Expression ]
...
0[0]
이러한 규칙을 준수 하므로 유효한 표현식으로 간주됩니다 . 그것이 올바른지 여부 (예 : 런타임에 오류가 발생하지 않음)는 또 다른 이야기이지만 그렇습니다. 이것은 JS가 someLiteral[someExpression]
다음 과 같은 표현식을 평가하는 방법입니다 .
- 평가
someExpression
(임의의 복잡 할 수 있음) - 리터럴을 해당 객체 유형으로 변환 (숫자 리터럴 =>
Number
, 문자열 =>String
등) get property
result (1) 속성 이름으로 result (2)에 대한 작업을 호출하십시오.- 결과 버리기 (2)
그래서 다음 0[0]
과 같이 해석됩니다.
index = 0
temp = Number(0)
result = getproperty(temp, index) // it's undefined, but JS doesn't care
delete temp
return result
다음은 유효 하지만 잘못된 표현식 의 예입니다 .
null[0]
파싱이 잘되었지만 런타임에 인터프리터가 2 단계에서 실패하고 ( null
객체로 변환 할 수 없기 때문에 ) 런타임 오류가 발생합니다.
답변
Javascript에서 유효하게 숫자를 아래 첨자 할 수있는 상황이 있습니다.
-> 0['toString']
function toString() { [native code] }
이 작업을 수행하려는 이유가 즉시 명확하지는 않지만 Javascript에서 첨자를 사용하는 것은 점 표기법을 사용하는 것과 동일합니다 (점 표기법이 식별자를 키로 사용하는 것을 제한하지만).
답변
이것이 유효한 구문 이 Javascript에 고유하지 않다는 점에 주목하고 싶습니다 . 대부분의 언어에는 런타임 오류 또는 유형 오류가 있지만 구문 오류와는 다릅니다. Javascript는 주어진 이름의 속성이없는 객체를 구독하는 경우를 포함하여 다른 언어가 예외를 발생시킬 수있는 많은 상황에서 undefined를 반환하도록 선택합니다.
이 구문은 표현식의 유형 (숫자 리터럴과 같은 간단한 표현식조차도)을 알지 못하므로 모든 연산자를 모든 표현식에 적용 할 수 있습니다. 예를 들어, 아래 첨자를 시도 undefined
하거나 Javascript에서 null
a TypeError
를 발생시킵니다 . 구문 오류가 아닙니다. 실행되지 않으면 (if- 문의 잘못된쪽에 있음) 문제가 발생하지 않는 반면 구문 오류는 정의상 항상 컴파일 타임 (eval, Function 등)에 포착됩니다. , 모두 컴파일로 계산).
답변
유효한 구문이기 때문에 해석 할 유효한 코드도 있습니다. 모든 객체의 속성에 액세스하려고 시도 할 수 있으며 (이 경우 0은 Number 객체로 캐스팅 됨) 값이 있으면 값을 제공하고 그렇지 않으면 정의되지 않습니다. 그러나 undefined 속성에 액세스하려고하면 작동하지 않으므로 0 [0] [0]은 런타임 오류를 발생시킵니다. 그래도 여전히 유효한 구문으로 분류됩니다. 유효한 구문과 런타임 / 컴파일 시간 오류를 일으키지 않는 것에는 차이가 있습니다.
답변
구문이 유효 할뿐만 아니라 undefined
대부분의 경우 결과가 정상일 필요는 없습니다. JS는 가장 순수한 객체 지향 언어 중 하나입니다. 대부분의 소위 OO 언어는 일단 생성 된 객체의 형태 (클래스에 묶여 있음)를 변경할 수없고 객체의 상태 만 변경할 수 있다는 점에서 클래스 지향적입니다. JS에서는 상태와 객체의 형태를 변경할 수 있으며 이는 생각보다 자주 수행합니다. 이 기능은 오용하는 경우 다소 모호한 코드를 만듭니다. 숫자는 불변이므로 객체 자체를 변경할 수 없으며 상태도 형태도 아니므로 할 수 있습니다.
0[0] = 1;
1을 반환하지만 실제로 아무것도 할당하지 않는 유효한 할당 표현식입니다 0
. 숫자 는 변경할 수 없습니다. 그 자체로는 다소 이상합니다. 아무것도 할당하지 않는 유효하고 올바른 (실행 가능한) 어싱먼트 표현식을 가질 수 있습니다 (*). 그러나 숫자의 유형은 변경 가능한 객체이므로 유형을 변경할 수 있으며 변경 사항은 프로토 타입 체인에 계단식으로 적용됩니다.
Number[0] = 1;
//print 1 to the console
console.log(0[0]);
//will also print 1 to the console because all integers have the same type
console.log(1[0]);
물론 정상적인 사용 범주와는 거리가 멀지 만 다른 시나리오에서는 개체 기능을 확장하는 것이 실제로 의미가 있기 때문에이를 허용하도록 언어가 지정되어 있습니다. jQuery 플러그인이 jQuery 객체에 연결하여 예제를 제공하는 방법입니다.
(*) 실제로 객체의 속성에 값 1을 할당하지만 해당 (transcient) 객체를 참조 할 수있는 방법이 없으므로 nexx GC 패스에서 수집됩니다.
답변
JavaScript에서는 모든 것이 객체이므로 인터프리터가 구문 분석 할 때 0을 객체로 취급하고 0을 속성으로 반환하려고합니다. true 또는 “”(빈 문자열)의 0 번째 요소에 액세스하려고 할 때도 같은 일이 발생합니다.
0 [0] = 1로 설정해도 속성과 그 값을 메모리에 설정하지만 0에 액세스하는 동안에는 숫자로 취급합니다 (여기서는 Object로 취급하는 것과 숫자로 취급하는 것 사이에 혼동하지 마십시오.)