JavaScript에서! {} [true]가 true로 평가되는 이유는 무엇입니까?


131

{}[true]이다 [true]하고 ![true]있어야한다 false.

그렇다면 왜 !{}[true]평가 true합니까?


30
var o = {}; o[true] === undefined.
azz

2
여기에 대한 설명은 이 이전 질문
IMSoP

45
"자바 스크립트가 바보이기 때문에"는 아마도 당신이 찾고있는 답이 아닙니다.
georg

2
언급했듯이 {}[true] === [true]콘솔에서 가져 오는 경우 {}이는 개체가 아닌 빈 코드 블록으로 취급되기 때문입니다 .
azz

3
그것을 도울 수 있다면, 비교하려고 {}({})콘솔 (또는 {}[true]({})[true]). 또한 아무도 언급하지 않았 듯이 object [true]는 object [ "true"]로 평가됩니다.
BiAiB

답변:


172

일반이 때문에 나는 그의를 생각 {}[true]포함한 배열 다음에 빈 문 블록 (안 객체 리터럴)로 구문 분석 true이다 true.

한편, 도포 !조작은 파서가 해석하게 {}이하가되도록, 오브젝트 리터럴로 {}[true]복귀하는 멤버 액세스하게 undefined하고 !{}[true]true(대로 !undefined이다 true).


25
반면! undefined가 사실이라는 사실은 여전히 ​​변명 할 수 없습니다.
evilcandybag

87
@evilcandybag : 절대 아닙니다. undefined거짓입니다 (우리가 자주 의존하는 것입니다- if (obj.maybeExists) ...). 그것은 논리적으로 완벽 !undefined합니다.
josh3736

8
@Josh, evilcandybag은 null일부 언어에서와 비슷한 동작을 선호한다고 생각 !undefined합니다 undefined. 그러나 Javascript에서는 그렇지 않습니다.
Frédéric Hamidi

6
@evilcandybag : 따라서 not undefined( !undefined) 인 것을 정의해야 한다는 것은 논리적으로 의미가 있습니다. 무언가가 정의되면 일반적으로로 해석됩니다 true.
OozeMeister

7
@Cruncher a가 정의되지 않고 b가 정의되지 않은 경우 어떻게 a! = b인지 알 수 있습니까? 특히 두 변수의 알려진 특성이 정확히 동일한 경우.
LJ2

44

때문에는 {}[true]반환하지 않습니다 true, 그러나 undefined, 그리고 undefined으로 평가된다 false:

http://jsfiddle.net/67GEu/

'use strict';
var b = {}[true];
alert(b); // undefined
b = !{}[true];
alert(b); // true

21
{}[true]콘솔에서 평가 하면 객체가 아닌 빈 코드 블록으로 해석 [true]되기 때문에 얻을 수 {}있습니다. 의 맥락과 모호성에 관한 것 {}입니다.
IMSoP

1
@IMSoP 그러나 왜 {key:"value"}[1,2,3];평가 [1,2,3]합니까?
t.niese

3
@ t.niese는 레이블 ( key:)과 문자열 리터럴 ( "value") 및 배열이 포함 된 명령문 블록으로 구문 분석되기 때문 입니다. 파서는 여전히 객체 리터럴을 보지 못합니다.
프레데릭 하 미디

1
@ FrédéricHamidi 아 그래, 그거야. 라벨을 억압했습니다 ^^
t.niese

1
@dooxe 다른 답변을 읽으십시오; 해석되는 맥락에 관한 것입니다. alert()또는로 감싸 거나 console.log()변수에 할당하면 컨텍스트가 변경되므로 콘솔에서 자체적으로 입력 한 것과 같은 방식으로 작동하지 않습니다.
IMSoP

27

때문에

{}[true]

로 평가 undefined되며 !undefined입니다 true.

@schlingel에서 :

true키 및 {}해시 맵으로 사용됩니다. 키가있는 속성이 true없으므로를 반환합니다 undefined. 아니 undefined되고 true, 같은 예상.

콘솔 세션 ( Node.js [0.10.17] ) :

> {}[true]
undefined
> !{}[true]
true
> [true]
[ true ]
> ![true]
false
>

그러나 Chrome 콘솔에서 :

> !{}[true]
true

따라서 불일치가 없습니다. 이전 버전의 JavaScript VM을 사용하고있을 것입니다. 추가 증거가 필요한 사람들을 위해 :

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

최신 정보

함께 파이어 폭스 , 그것은 또한 평가 true:

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


eval('{}[true]')콘솔에 입력하거나 입력 하면 안됩니다 . 그렇다면 예를 들어 als {}"test"test또는 심지어 {key:"value"}"test"입니다 test.
t.niese

흥미롭게도 어떤 js 엔진에서 테스트합니까?
t.niese

@ t.niese 방금 노드 콘솔에 입력했는데 이것이 내가 얻은 것입니다.
게임 Brainiac

호기심을 위해서. {}[true];( ;) [true]가 당신을 위해 돌아왔습니까 ?
t.niese

2
downvote 놈들의 이유? 거기에있다 거의 8 투표 이것에 동일한 답변을, 그리고 내가 downvote을 얻을? 내가 뭘 잘못 했어?
게임 Brainiac

23

혼란의 이유는 첫 번째 주장을 오해하기 때문입니다.

{}[true] 이다 [true]

실행할 때보고있는 것은 모호한 결과입니다. Javascript는 이와 같은 모호성을 처리하는 방법에 대해 정의 된 규칙 세트를 가지고 있으며,이 경우, 단일 명령문으로 표시되는 내용을 두 개의 개별 명령문으로 나눕니다.

따라서 Javascript는 위의 코드를 두 개의 별도 명령문으로 간주합니다. 첫째, {}가 있고 완전히 별개 [true]입니다. 두 번째 진술은 결과를 제공하는 것 [true]입니다. 첫 번째 진술 {}은 실질적으로 완전히 무시됩니다.

다음을 시도하여이를 증명할 수 있습니다.

({}[true])

즉, 인터프리터가 단일 명령문으로 읽도록 강제로 전체를 괄호로 묶습니다.

이제 문장의 실제 가치는 undefined입니다. (이것은 나중에 다음 부분을 이해하는 데 도움이 될 것입니다)

이제 우리는 귀하의 질문의 첫 부분이 빨간 청어라는 것을 알고 있으므로 질문의 마지막 부분으로 넘어 갑시다.

그렇다면 왜! {} [true]가 true로 평가됩니까?

여기에도 같은 문장이 있지만 !그 앞에 추가됩니다.

이 경우 Javascript의 규칙은 전체 내용을 단일 문으로 평가하도록 지시합니다.

앞의 문장을 괄호로 묶었을 때 일어난 일을 다시 참조하십시오. 우리는 얻었다 undefined. 이번에는 효과적으로 똑같은 일을하지만 그 일 !을 앞두고 있습니다. 그래서 코드는 다음과 같이 간단하게 할 수 !undefined있는, true.

잘만되면 그것은 조금 설명합니다.

복잡한 짐승이지만 여기서 배우는 교훈은 콘솔에서 문장을 평가할 때 괄호를 사용하여 가짜 결과를 피하는 것입니다.


2
나는 생각하지 않는다는 {}[true]것입니다 무효 정확히 단지 모호한 . "빈 코드 블록 다음에 배열 리터럴"또는 "속성이없는 오브젝트 리터럴"로 해석 될 수 있습니다. 첫 번째가 기술적으로 ASI의 사례인지는 모르겠지만 (많은 언어는 세미콜론을 넣지 않을 것입니다) 문제의 핵심은 상황에 맞는 해석입니다.
IMSoP

@IMSoP-댓글을 게시하기 전에 이미 답변을 편집했습니다. :)
Spudley

1
대답의 시작 부분에 여전히 "{} [true]은 (는) 실제로 유효하지 않습니다"라는 메시지가 표시됩니다.
IMSoP

또한, OP는 "말을하지 않았다 {}[true]이다 true그들은"며 " {}[true]입니다 [true]모호한 문장의 두 개의 유효한 해석 중 하나입니다".
IMSoP

14

{}[true]입니다 undefined. 이것을 작성하려면 다음을 작성하십시오.

a = {};
a[true] === undefined // true

또는 간단히 :

({})[true] === undefined // true

우리는 알고 !undefined있다 true.


에서 @Benjamin Gruenbaum의 대답 :

Chrome dveloper 도구는 다음을 수행합니다 .

  try {
      if (injectCommandLineAPI && inspectedWindow.console) {
          inspectedWindow.console._commandLineAPI = new CommandLineAPI(this._commandLineAPIImpl, isEvalOnCallFrame ? object : null);
          expression = "with ((window && window.console && window.console._commandLineAPI) || {}) {\n" + expression + "\n}";
      }
      var result = evalFunction.call(object, expression);
      if (objectGroup === "console")
          this._lastResult = result;
      return result;
  } 
  finally {
      if (injectCommandLineAPI && inspectedWindow.console)
          delete inspectedWindow.console._commandLineAPI;
  }

따라서 기본적으로 call표현식으로 객체를 수행합니다 . 표현은 다음과 같습니다.

with ((window && window.console && window.console._commandLineAPI) || {}) {
    {}+{};// <-- This is your code
}

보시다시피, 랩핑 괄호없이 표현식이 직접 평가됩니다.

자세한 내용은 이 질문 에서 찾을 수 있습니다 .


10

여기에 대한 답변이 좋습니다. 여기 의사 코드에 대한 분석이 있습니다.

  • {}['whatever'] = 빈 블록, NewArray ( 'whatever') = NewArray ( 'whatever')
  • {}[true] = 빈 블록, NewArray (true) = NewArray (true)
  • !{}['whatever'] = LogicalNOT (convertToBool (NewObject.whatever)) = LogicalNOT (convertToBool (undefined)) = LogicalNOT (false) = true
  • ({}['whatever']) = 그룹화 (NewObject.whatever) = 그룹화 (정의되지 않음) = 정의되지 않음

8

이것은 {}의미에서의 리터럴 표현이 Object아니라 빈 범위 (또는 빈 코드 블록) 이기 때문에 발생합니다 .

{ var a = 1 }[true] // [true] (do the same thing)

범위 내에서 코드를 평가 한 다음 배열을 보여줍니다.

그리고 당신의

!{}[true]

이 범위를 int로 변환하고 동일한 배열을 true로 반환하십시오. 이 코드에는 부울 검사가 없습니다.

그리고 결과를 확인하려고하면 다음과 같은 결과가 나타 {}[true]납니다 false.

{}[true] -> [true] -> ![true] -> false

더 이상 범위가 없으므로.

따라서 !귀하의 질문에 다음과 같이하십시오 :

!function() {
   //...
}

당신이하면 더 쉽게 볼 수 있습니다 var x = {}; x[true].
Chris Hayes

1
"이 범위를 int로 변환합니다"라는 것이 무슨 의미인지 잘 모르겠습니다. 내가 선두에 생각 !되어 빈 개체가 아닌 범위로 해석하고,이 불일치이다.
IMSoP

6
  • {} 속성이없는 객체입니다.
  • []객체 바로 뒤에 있기 때문에 "배열 만들기"가 아니라 "이 이름의 속성에 액세스"를 의미합니다
  • true부울이지만 속성 이름으로 사용되므로 문자열 ( "true")로 캐스트됩니다.
  • 개체라는 속성이 없습니다 true(이 속성이 없습니다 때문에) 너무 {}['true']하다undefined
  • !undefinedundefined부울로 캐스팅 ( false)
  • not 연산자가 false로 바뀝니다 true.

2
의 경우 {}[true](다른 컨텍스트) {}입니다 하지 프로퍼티가없는 객체는 빈 코드 블록입니다.
IMSoP


4

조금 더 놀자!

먼저 재미있게 놀자! :

//----------#01#-----------
{}[true]; //[true]

//----------#02#-----------
var a = {}[true]; 
      console.log(a); //undefined

//----------#03#-----------
{ b: 12345 }[true]; //[true]

//----------#04#-----------
{ b: 12345 }["b"]; //evaluates to ["b"] ?!?

//----------#05#-----------
{ b: 12345 }.b; // "Unexpected token ."

//----------#06#-----------
({ b: 12345 }).b; //12345

//----------#07#-----------
var c = { b: 12345 }.b; 
      console.log(c); //12345

//----------#08#-----------
var c = { b: 12345 }["b"];
      console.log(c); //12345

//----------#09#-----------
{ true: 54321 }[true]; // "SyntaxError: Unexpected token : "

//----------#10#-----------
var d = { true: 54321 }[true]; //No error here ¬¬
      console.log(d); //54321

//----------#11#-----------
!{}[true]; // true

자,이 미친 행동을 하나씩 이해해 봅시다 :

1) 여기서는 {}빈 코드 블록으로 구문 분석됩니다. 할당, 부정, 그룹화 (괄호 포함) 또는 구문 분석기에 이것이 {}객체 리터럴 임을 나타내는 구문이 없으면 기본 가정은 단순히 쓸모없는 빈 블록이라고 생각하는 것입니다.

이것은이 동작의 증거입니다.

{ alert(123) }[true]

위의 코드는 경고를 정상적으로 표시 [true]하며 같은 방식 으로로 평가됩니다 {}[true].

세미콜론이없는 블록 문장

블록 타입 문장은 그 뒤에 세미콜론이 필요하지 않습니다.

예를 들어 :

for(var i=0; i < 1; i++){}function a(){};alert("Passed here!");if(true){}alert("Passed here too!")

두 가지 경고가 모두 표시됩니다.

따라서 세미콜론이없는 빈 블록 명령문은 유효하며 아무 것도 수행하지 않습니다. 이렇게 {}[true]하면 개발자 도구 (또는 Firebug) 콘솔에 입력 할 때 평가 된 값이 마지막 표현식 명령문 의 값이 됩니다. 이 경우 마지막 표현식은 [true]입니다.

2) 할당 컨텍스트에서 파서는 {}객체 리터럴 인지 확인합니다 . var a =을 수행하면 {}[true]모호성을 제거 {}하고 블록 문이 아닌 파서를 끝냅니다 .
그래서 여기서는 "true"빈 객체에서 키로 값을 얻으려고 합니다. 분명히이 키 이름과 키-값 쌍이 없습니다. 이런 식으로 변수는 정의되지 않습니다.

예약 된 단어를 객체 키로

ECMAScript 5를 사용하면 객체 키를 예약어로 사용할 수 있습니다. 따라서 다음 키가 합법적입니다.

var obj = {if: 111, for: 222, switch: 333, function: 444, true: 555}

3) 예제 1 과 동일한 설명 . 그러나 ... { b: 12345 }부품이 블록 문으로 취급되면 b: 12345문 유형은 무엇 입니까 ??

... (?????)

그것은 레이블 문장입니다 , 당신은 이미 전에 보았습니다 ... 그것은 루프와에서 사용됩니다 switch. 레이블 문장에 대한 몇 가지 흥미로운 링크는 다음과 같습니다. 1 , (2) [ Javascript의 중첩 루프에서 벗어날 수있는 가장 좋은 방법은 무엇입니까? , (3) [ 자바 스크립트에서 중첩 루프를 끊는 방법? .

참고 : 이것을 평가하십시오.

{a: 1, b: 2} //=>>>SyntaxError: Unexpected token :

레이블 문은 쉼표 연산자로 구분할 수 없으므로 세미콜론으로 구분해야합니다. 그래서 이것은 유효합니다 :{a: 1; b: 2}

4) 예제 13에 대한 설명을 참조하십시오 ...

5) 한 번 더, 우리는 { b: 12345 }코드 블록으로 취급되고 있으며 점 표기법 을 사용하여 코드 블록의 속성에 액세스하려고하는데 , 이것이 허용되지 않으며 파서는 "Unexpected token :"예외를 던집니다 .

6) 코드는 위의 예제와 거의 동일하지만 { b: 12345 }구문을 표현식 그룹화 연산자 로 둘러싸면 구문 분석기는 이것이 객체임을 알게됩니다. 이런 식으로, 당신은 "b"일반적으로 속성 에 액세스 할 수 있습니다 .

7) 예제 2를 기억하십시오. 여기서 할당이 있고 파서는 그것이 { b: 12345 }객체 라는 것을 알고 있습니다.

8) 위 예제와 동일하지만 점 표기법 대신 대괄호 표기법을 사용합니다 .

9)"identifier: value" 블록 구문 내 에서이 구문은 레이블 이라고 이미 말했습니다 . 그러나 레이블 이름은 예약 된 키워드 (객체 속성 이름과 반대)가 될 수 없다는 것도 알아야합니다. 우리라는 라벨을 정의했을 때 "true", 우리는있어 SyntaxError.

10) 다시, 우리는 객체를 다루고 있습니다. 예약어를 사용하는 데 아무런 문제가 없습니다. =)

11) 마지막으로, 우리는 이것을 가지고 있습니다 :!{}[true]

여기서 물건을 분리합시다.

a)는 부정함으로써, 우리는이 것을 파서에 알리는 것 {}입니다 오브젝트 .

예에 도시 된 바와 같이, b) 2 하는 {}객체라는 속성이없는 true이런 식으로 계산한다 그래서 undefined.

c) 최종 결과는 undefined가치 의 부정이다 . Javascript는 암시 적 유형 변환을 수행 하며 undefined값이 잘못되었습니다 .

d) 따라서 부정 false은 ... true!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.