もう少し遊ぼう!
まず、楽しみましょう!:
//----------#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!
var o = {}; o[true] === undefined。