音の鳴るブログ

鳴らないこともある

JavaScript か CoffeeScript かで結果が変わるプログラム

使い所皆無なんだけど、このプログラムは JavaScript だと "JavaScript" と評価されて CoffeeScript だと "CoffeeScript" と評価される。

{ JavaScript: ["CoffeeScript"] }["JavaScript"][0]

検証用コード

code = '{ JavaScript: ["CoffeeScript"] }["JavaScript"][0]';

// "CoffeeScript" と評価される
eval(CoffeeScript.compile(code, {bare:true}));

// "JavaScript" と評価される
eval(code);

こうしてしまうと、観察者効果でどちらでも "CoffeeScript" と評価されてしまう。

a = { JavaScript: ["CoffeeScript"] }["JavaScript"][0]

"JavaScript"と評価される仕組み

JavaScript{ にはオブジェクトリテラルの開始とブロックの開始、関数の本体部分の開始という3つの役割りがある。 細かいことは ECMA262 に書いてあるけど、雑に説明するとそれらは出現位置で決定されて、文頭の { はブロックと解釈される。a に代入するケースだと文頭ではなく式の先頭になるのでオブジェクトリテラルとして解釈される。

上記のコードを Esprima でパースすると、このようになる。

Esprima: Parser - {JavaScript:["CoffeeScript"]}["JavaScript"][0]

こういう感じで Block と ExpressionStatement として解釈される。

{ // ブロック
    JavaScript: // ラベル
        ['CoffeeScript']; // 配列
}
['JavaScript'][0]; // 配列[0]

"CoffeeScript"と評価される仕組み

CoffeeScript{ にはオブジェクトリテラルとしての役割しかないので、オブジェクトリテラルとして解釈される。その際、先のJavaScriptの仕様を回避するため ( ) で囲んでくれる。

({
  JavaScript: ["CoffeeScript"]
})["JavaScript"][0];