[javascript] 0 [0]이 구문 적으로 유효한 이유는 무엇입니까?

이 줄이 자바 스크립트에서 유효한 이유는 무엇입니까?

var a = 0[0];

그 후, a이다 undefined.



답변

당신이 할 때 0[0] 하면 JS 인터프리터는 첫 번째 0Number객체 로 변환 한 다음 [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 ]

그리고 비슷하게 ExpressionNumericLiteral 문법을 따른 후에도 결국 그렇게 될 수 있습니다 .

NumericLiteral [ NumericLiteral ]

이는 0[0]문법의 허용 된 부분이므로 SyntaxError가 없음을 의미합니다 .


그런 다음 런타임에 읽고있는 undefined소스가 객체이거나 객체에 대한 암시 적 변환이있는 한 존재하지 않는 속성을 읽을 수 있습니다 (단지로 읽음 ). 그리고 숫자 리터럴은 실제로 객체 (Number 객체)로 암시 적으로 변환됩니다.

이것은 자바 스크립트의 알려지지 않은 기능 중 하나입니다. 유형 Number, BooleanString 자바 스크립트는 일반적으로 프리미티브 (안 완전한 객체)로 내부적으로 저장됩니다. 이것은 컴팩트하고 변경 불가능한 스토리지 표현입니다 (아마도 구현 효율성을 위해이 방식으로 수행됨). 그러나 Javascript는 이러한 기본 요소를 속성 및 메서드가있는 객체처럼 처리 할 수 ​​있기를 바랍니다. 따라서 프리미티브에서 직접 지원되지 않는 속성이나 메서드에 액세스하려고하면 Javascript는 값이 프리미티브의 값으로 설정된 적절한 유형의 객체로 프리미티브를 일시적으로 강제합니다.

와 같은 기본 요소에서 객체와 유사한 구문을 사용하면 0[0]인터프리터는이를 기본 요소에 대한 속성 액세스로 인식합니다. 이에 대한 응답은 첫 번째 0숫자 프리미티브 를 가져 와서 속성에 Number액세스 할 수 있는 완전한 객체 로 강제 변환하는 것 [0]입니다. 이 특정 경우 [0]에는 Number 객체 의 속성 undefined이에서 얻은 값입니다 0[0].

다음은 속성을 처리하기 위해 기본 요소를 객체로 자동 변환하는 방법에 대한 기사입니다.

자바 스크립트 프리미티브의 비밀스런 삶


다음은 ECMAScript 5.1 사양의 관련 부분입니다.

9.10 CheckObjectCoercible

값이 undefined또는 이면 TypeError를 던지고 null, 그렇지 않으면를 반환합니다 true.

여기에 이미지 설명 입력

11.2.1 속성 접근 자

  1. baseReference를 MemberExpression을 평가 한 결과로 둡니다.
  2. baseValue를 GetValue (baseReference)로 둡니다.
  3. propertyNameReference를 Expression 평가의 결과로 둡니다.
  4. propertyNameValue를 GetValue (propertyNameReference)로 둡니다.
  5. CheckObjectCoercible (baseValue)를 호출합니다.
  6. propertyNameString을 ToString (propertyNameValue)로 둡니다.
  7. 평가되는 구문 생성이 Strict 모드 코드에 포함되어 있으면 strict를 true로, 그렇지 않으면 strict를 false로 둡니다.
  8. 기본 값이 baseValue이고 참조 된 이름이 propertyNameString이고 엄격 모드 플래그가 엄격한 Reference 유형의 값을 반환합니다.

이 질문에 대한 작동 부분은 위의 5 단계입니다.

8.7.1 GetValue (V)

액세스되는 값이 속성 참조 일 때 ToObject(base)모든 기본 요소의 객체 버전을 가져 오기 위해 호출하는 방법을 설명합니다 .

9.9 ToObject

이는 Boolean, NumberString프리미티브가 [[PrimitiveValue]] 내부 속성이 적절히 설정된 객체 형태로 변환되는 방법을 설명합니다 .


흥미로운 테스트로, 코드가 다음과 같으면 :

var x = null;
var a = x[0];

이 기술적으로 법적 구문으로 아직 구문 분석시에 구문 에러가 발생하지 것입니다,하지만 당신은 코드를 실행하면 속성 접근 자 로직 위의이 값에 적용될 때 때문에 런타임에서 형식 오류를 던질 것 x, 그것은 호출 CheckObjectCoercible(x)또는 호출 ToObject(x)하는 경우 모두 형식 오류가 발생합니다 x입니다 nullundefined.


답변

대부분의 프로그래밍 언어와 마찬가지로 JS는 문법을 사용하여 코드를 구문 분석하고 실행 가능한 형식으로 변환합니다. 특정 코드 청크에 적용 할 수있는 문법 규칙이 없으면 SyntaxError가 발생합니다. 그렇지 않으면 코드가 의미가 있는지 여부에 관계없이 유효한 것으로 간주됩니다.

JS 문법 의 관련 부분은 다음 과 같습니다.

Literal ::
   NumericLiteral
   ...

PrimaryExpression :
   Literal
   ...

MemberExpression :
   PrimaryExpression
   MemberExpression [ Expression ]
   ...

0[0]이러한 규칙을 준수 하므로 유효한 표현식으로 간주됩니다 . 그것이 올바른지 여부 (예 : 런타임에 오류가 발생하지 않음)는 또 다른 이야기이지만 그렇습니다. 이것은 JS가 someLiteral[someExpression]다음 과 같은 표현식을 평가하는 방법입니다 .

  1. 평가 someExpression(임의의 복잡 할 수 있음)
  2. 리터럴을 해당 객체 유형으로 변환 (숫자 리터럴 => Number, 문자열 => String등)
  3. get propertyresult (1) 속성 이름으로 result (2)에 대한 작업을 호출하십시오.
  4. 결과 버리기 (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에서 nulla 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로 취급하는 것과 숫자로 취급하는 것 사이에 혼동하지 마십시오.)