development

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

big-blog 2020. 7. 16. 07:41
반응형

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


이 줄이 javascript에서 왜 유효합니까?

var a = 0[0];

그 후에 aundefined입니다.


당신이 할 때 0[0]의 JS 인터프리터는 처음으로 바뀔 것이다 0Number객체 다음에 액세스하려고 [0]입니다 개체의 속성을 undefined.

0[0]이 컨텍스트에서 언어 문법에 의해 속성 액세스 구문 이 허용 되므로 구문 오류가 없습니다 . 이 구조 (자바 스크립트 문법에서 용어 사용)는 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 객체)로 암시 적으로 변환됩니다.

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

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

다음은 속성을 다루기 위해 프리미티브를 객체로 자동 변환하는 기사입니다.

자바 스크립트 프리미티브의 비밀 생활


ECMAScript 5.1 사양의 관련 부분은 다음과 같습니다.

9.10 CheckObjectCoercible

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

여기에 이미지 설명을 입력하십시오

11.2.1 속성 접근 자

  1. Let baseReference be the result of evaluating MemberExpression.
  2. Let baseValue be GetValue(baseReference).
  3. Let propertyNameReference be the result of evaluating Expression.
  4. Let propertyNameValue be GetValue(propertyNameReference).
  5. Call CheckObjectCoercible(baseValue).
  6. Let propertyNameString be ToString(propertyNameValue).
  7. If the syntactic production that is being evaluated is contained in strict mode code, let strict be true, else let strict be false.
  8. Return a value of type Reference whose base value is baseValue and whose referenced name is propertyNameString, and whose strict mode flag is strict.

An operative part for this question is step #5 above.

8.7.1 GetValue (V)

This describes how when the value being accessed is a property reference, it calls ToObject(base) to get the object version of any primitive.

9.9 ToObject

This describes how Boolean, Number and String primitives are converted to an object form with the [[PrimitiveValue]] internal property set accordingly.


As an interesting test, if the code was like this:

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

It would still not throw a SyntaxError at parse time as this is technically legal syntax, but it would throw a TypeError at runtime when you run the code because when the above Property Accessors logic is applied to the value of x, it will call CheckObjectCoercible(x) or call ToObject(x) which will both throw a TypeError if x is null or undefined.


Like most programming languages, JS uses a grammar to parse your code and convert it to an executable form. If there's no rule in the grammar that can be applied to a particular chunk of code, it throws a SyntaxError. Otherwise, the code is considered valid, no matter if it makes sense or not.

The relevant parts of the JS grammar are

Literal :: 
   NumericLiteral
   ...

PrimaryExpression :
   Literal
   ...

MemberExpression :
   PrimaryExpression
   MemberExpression [ Expression ]
   ...

Since 0[0] conforms to these rules, it's considered a valid expression. Whether it's correct (e.g. doesn't throw an error at run time) is another story, but yes it is. This is how JS evaluates expressions like someLiteral[someExpression]:

  1. evaluate someExpression (which can be arbitrary complex)
  2. convert the literal to a corresponding object type (numeric literals => Number, strings => String etc)
  3. call the get property operation on result(2) with the property name result(1)
  4. discard result(2)

So 0[0] is interpreted as

index = 0
temp = Number(0)
result = getproperty(temp, index) // it's undefined, but JS doesn't care
delete temp
return result

Here's a example of a valid, but incorrect expression:

null[0]

It's parsed fine, but at run time, the interpreter fails on step 2 (because null can't be converted to an object) and throws a run time error.


There are situations where you could validly subscript a number in Javascript:

-> 0['toString']
function toString() { [native code] }

While not immediately apparent why you would want to do this, subscripting in Javascript is equivalent to using dotted notation (albeit the dot notation limits you to using identifiers as keys).


I'd just like to note that this being valid syntax is not in any way unique to Javascript. Most languages will have a runtime error or a type error, but that's not the same thing as a syntax error. Javascript chooses to return undefined in many situations where another language might raise an exception, including when subscripting an object that does not have a property of the given name.

The syntax doesn't know the type of an expression (even a simple expression like a numeric literal), and will allow you to apply any operator to any expression. For example, attempting to subscript undefined or null causes a TypeError in Javascript. It's not a syntax error - if this is never executed (being on the wrong side of an if-statement), it won't cause any problems, whereas a syntax error is by definition always caught at compile time (eval, Function, etc, all count as compiling).


Because it is valid syntax, and even valid code to be interpreted. You can try to access any property of any object(and in this case 0 will be cast to a Number-object), and it will give you the value if it exists, otherwise undefined. Trying to access a property of undefined does not work however, so 0[0][0] would result in a runtime error. This would still be classified as valid syntax though. There's a difference of what is valid syntax and what won't cause runtime/compiletime errors.


Not only is the syntax valid the result does not have to be undefined though in most, if not all sane cases it will. JS is one of the most pure object oriented languages. Most so called OO languages are class oriented, in the sense that you can't change the form (it's tied to the class) of the object once created, only the state of the object. In JS you can change the state as well as the form of the object and this you do more often than you think. This ability makes for some rather obscure code, if you misuse it. Numerals are immutable, so you can't change the object itself, not it's state nor it's form so you could do

0[0] = 1;

which is an valid assignment expression that returns 1 but doesn't actually assign anything, The numeral 0 is immutable. Which in itself is somewhat odd. You can have a valid and correct (executable) assingment expression, that doesn't assign anything(*). However the type of the numeral is a mutable object so you can mutate the type, and the changes will cascade down the prototype chain.

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]); 

of course it's a far cry from the sane use category but the language is specified to allow for this because in other scenarios, extending the objects capabilities actually makes a lot of sense. It's how jQuery plugins hook into the jQuery object to give an example.

(*) 실제로 값 1을 객체의 속성에 할당하지만 해당 (초과) 객체를 참조 할 수있는 방법이 없으므로 nexx GC 패스에서 수집됩니다.


JavaScript에서는 모든 것이 객체이므로 인터프리터가 구문 분석 할 때 0을 객체로 취급하고 0을 속성으로 반환하려고 시도합니다. true 또는 ""(빈 문자열)의 0 번째 요소에 액세스하려고 할 때도 마찬가지입니다.

0 [0] = 1을 설정하더라도 속성과 속성 값을 메모리에 설정하지만 0에 액세스하는 동안 숫자로 취급합니다 (여기서 Object와 숫자로 취급하는 것을 혼동하지 마십시오).

참고 URL : https://stackoverflow.com/questions/29250950/why-is-00-syntactically-valid

반응형