JavaScriptで!{} [true]がtrueと評価されるのはなぜですか?


131

{}[true]である[true]![true]する必要がありますfalse

では、なぜ !{}[true]評価するのtrueですか?


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

2
ここでの説明は、前の質問で
IMSoP '31

45
「Javascriptはばかげているから」はあなたが探している答えではないでしょう。
georg 2013年

2
前述のように、{}[true] === [true]コンソールから取得している場合、それは{}オブジェクトではなく空のコードブロックとして扱われているためです。
azz 2013年

3
それが役立つ場合は、コンソールで比較{}してみてください({})(または{}[true]および({})[true])。また、誰も言及していないように、object [true]はobject ["true"]と評価されます。
BiAiB 2013年

回答:


172

それは、plain {}[true]が(オブジェクトリテラルではなく)空のステートメントブロックとして解析され、その後にを含む配列が続くためtrueですtrue

一方、印加!オペレータはパーサが解釈することができる{}次のように、オブジェクトリテラルとして{}[true]返すそのメンバへのアクセスとなりundefined、そして!{}[true]実際にあるtrue(よう!undefinedですtrue)。


25
一方、!undefinedがtrueであるという事実は、まだ許されません。
evilcandybag 2013年

87
@evilcandybag:それは絶対に違います。 undefined偽物(私たちが頻繁に依存するもの- if (obj.maybeExists) ...)であるため、これ!undefinedは真実であり、完全に論理的に理解できます。
josh3736 2013年

8
@Josh、私はevilcandybagはと同類の行動を好むだろうと思うnullと、いくつかの言語で!undefinedに等しいですundefined。ただし、JavaScriptではそうではありません。
フレデリックハミディ2013年

6
@evilcandybag:それだけであることに何か言って論理的な意味がありますnot undefined!undefined)は、したがって、定義する必要があります。何かが定義されている場合、通常はと解釈されtrueます。
OozeMeister 2013年

7
@Cruncher aが未定義で、bが未定義の場合、a!= bであることをどうやって確認できますか?特に、2つの変数の唯一の既知の特性がまったく同じである場合。
LJ2 2013年

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 2013年

1
@IMSoPが{key:"value"}[1,2,3];評価されるのはなぜ[1,2,3]ですか?
t.niese 2013年

3
@ t.niese。これは、ラベル(key:)と文字列リテラル("value")を含み、その後に配列が続くステートメントブロックとして解析されるためです。パーサーはまだオブジェクトリテラルを見ません。
フレデリックハミディ2013年

1
@FrédéricHamidiああ、そうだね。私はラベルを
弾いた

1
@dooxe他の回答を読んでください。それはそれが解釈される文脈についてすべてです。alert()またはconsole.log()でラップするか、変数に割り当てると、コンテキストが変更されます。そのため、コンソールで単独で入力した場合と同じように動作しません。
IMSoP 2013年

27

なぜなら

{}[true]

はに評価されundefined!undefinedですtrue

@schlingelから:

trueキーおよび{}ハッシュマップとして使用されます。キーを持つプロパティが存在しないtrueため、返されますundefined。期待どおり、でundefinedはありませんtrue

コンソールセッション(Node.js [0.10.17]):

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

ただし、Google Chromeコンソールでは:

> !{}[true]
true

したがって、矛盾はありません。おそらく古いバージョンのJavaScript VMを使用しています。さらなる証拠が必要な場合:

ここに画像の説明を入力してください

更新

Firefoxの、それはまたに評価しますtrue

ここに画像の説明を入力してください


eval('{}[true]')それをコンソールに入力または入力した場合はできません。そして、例えばALSは{}"test"あるtestかさえ{key:"value"}"test"ありますtest
t.niese 2013年

面白いですが、どのjsエンジンでテストしますか?
t.niese 2013年

@ t.nieseノードコンソールに入力したところ、これが得られたものです。
Games Brainiac 2013年

好奇心のためだけに。い{}[true];(と;リターン)[true]、ここでそれがないので、あなたのために?
t.niese 2013年

2
反対票を投じる理由は?これとほぼ同じ答えが8票あり、私は反対票を得ますか?何を間違えたのですか?
Games Brainiac 2013年

23

混乱の理由は、最初の主張の誤解にあります。

{}[true] です [true]

実行したときに目にするのは、あいまいさの結果です。JavaScriptには、このようなあいまいさを処理する方法に関する一連のルールが定義されており、この場合は、単一のステートメントとして表示されるものを2つの別々のステートメントに分割します。

したがって、JavaScriptは上記のコードを2つの別個のステートメントと見なします。最初にがあり、{}次に完全に別個のがあり[true]ます。2番目のステートメントは、結果をもたらすもの[true]です。最初のステートメント{}は効果的に完全に無視されます。

次のことを試して、これを証明できます。

({}[true])

つまり、全体を括弧で囲んで、インタープリターにそれを単一のステートメントとして読み取らせる。

これで、ステートメントの実際の値がであることがわかりますundefined。(これは、後で次の部分を理解するのにも役立ちます)

これで、質問の最初の部分は赤いニシンであることがわかったので、質問の最後の部分に移りましょう。

では、なぜ!{} [true]がtrueと評価されるのでしょうか。

ここでは、同じステートメントがあり!ますが、前に追加されています。

この場合、JavaScriptのルールは、全体を単一のステートメントとして評価するように指示しています。

前のステートメントを角括弧で囲んだときに何が起こったかをもう一度参照してください。私たちは得たundefined。今回は、実質的に同じことを行っていますが!、前に配置しています。したがって、コードは!undefined、つまりに簡略化できますtrue

うまくいけば、それは少しそれを説明します。

これは複雑な獣ですが、ここで学ぶべき教訓は、コンソールでステートメントを評価するときにステートメントの前後にブラケットを使用して、このような偽の結果を回避することです。


2
正確に無効である{}[true]は思いません。あいまいです。これは、「空のコードブロックの後に配列リテラルが続く」または「プロパティがなく、プロパティにアクセスしているオブジェクトリテラル」として解釈できます。最初の問題が技術的にASIのケースであるかどうかはわかりません(多くの言語ではセミコロンがそこに配置されません)が、問題の中心となるのは状況依存の解釈です。
IMSoP 2013年

@IMSoP-あなたがコメントを投稿する前に、私はすでに回答を編集していました。:)
Spudley 2013年

1
回答の冒頭には、まだ「{} [true]は実際にはまったく有効ではない」と書かれています。
IMSoP 2013年

また、OPは " {}[true]is true"彼らが言った " {}[true]is [true]" とは言いませんでした。これは、あいまいなステートメントの2つの有効な解釈の1つです。
IMSoP 2013年

14

{}[true]ですundefined。それを見つけるにはこれを書いてください:

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

または単に:

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

それは知って!undefinedtrueます。


@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']) = Grouping(NewObject.whatever)= Grouping(undefined)= undefined

8

これは{}、あなたの意味ではのリテラル表現でObjectはなく、空のスコープ(または空のコードブロック)であるために発生します。

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

スコープ内のコードを評価し、配列を表示するだけです。

そしてあなたから

!{}[true]

このスコープに変換して、同じ配列をtrueに戻すだけです。このコードにはブールチェックはありません。

そして、あなたがあなたから結果をチェックしようとすると、あなたは{}[true]あなたを得るでしょうfalse

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

もうスコープがないので。

だから!あなたの質問で同じことをしてください:

!function() {
   //...
}

これを行うと、より簡単に確認できますvar x = {}; x[true]
クリスヘイズ

1
「converts to int this scope」の意味がわかりません。リーディング!スコープではなく空のオブジェクトとして解釈されると思いますが、これは矛盾です。
IMSoP 2013年

6
  • {} プロパティのないオブジェクトです。
  • ので[]、すぐにオブジェクトを次の、それが「アクセスこの名前のプロパティ」及びませんが、「アレイの作成」を意味します
  • trueブール値ですが、プロパティ名として使用されているため、文字列("true")にキャストされます
  • オブジェクトにはtrue(プロパティがないため)というプロパティがないため{}['true']undefined
  • !undefinedundefinedブール(false)にキャストします
  • ないオペレータのターンfalsetrue

2
以下の場合には{}[true](他の文脈で)、{}あるいないない特性を有するオブジェクトは、空のコードブロックです。
IMSoP 2013年


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つずつ理解してみましょう。

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"は、空のオブジェクトからキーを使用して値を取得しようとしています。明らかに、このキー名を持つキーと値のペアはありません。このように、a変数は未定義です。

オブジェクトキーとしての予約語

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)[ JavaScriptでネストされたループを解除する方法は?

注:これを評価してみてください:

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

ラベルステートメントはカンマ演算子で区切ることはできません。セミコロンで区切る必要があります。したがって、これは有効です:{a: 1; b: 2}

4)1および3の説明を参照してください...

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.