2010-02-17

訳の分からないJavascriptのコード

wtfjs: I’m certain that this will end all debate about where curly braces belong… right?

function laugh_undefined()
{
  return
  {
    haha: "ha!"
  };
}
laugh_undefined();
// returns undefined
 
function laugh_okey() {
  return { haha: "ha!" };
}
laugh_okey();
// returns Object: { haha: "ha!" }

そんなバカな。期待と違う動作をするではないか。しかも、まともな解説がない。

I’m certain that this will end all debate about where curly braces belong… right?

とあるだけだ。

ここは、私が持っている唯一の能力である、「規格を読む程度の能力」を発揮する時だ。さっそく規格にあたろう。

まず、何が問題なのか。私は、この二つの関数が、全く同じように動作し、どちらも、オブジェクトを返すことを期待している。それなのに、laugh_undefinedの方は、undefinedを返す。これは一体どういう事なのか。

まず、{ haha: "ha!" }というexpressionだが、これは、規格では、Object Initialiserと呼ばれている。これは、改行があろうとなかろうと関係がない。

まてよ、もしかしたら、{}をBlock statementと解釈しているのではあるまいか。規格を調べたところ、果たして、名前通りの、Block statementは存在した。いやしかし、もしこれがBlockと解釈されているのなら、haha: "ha!"、は、文法エラーである。しかし、どのブラウザも、文法エラーを指摘しない。ということは、どちらも、Object Initialiserと解釈されているはずだ。

とにかく、return statementは、もしかしたら、expressionではなく、statementを期待しているのかもしれない。そうであれば、Blockが優先されるはずだ。ブラウザが文法エラーを出さないのは、単に実装の問題なのかもしれない。さっそく、return statementを調べよう。

return [no LineTerminator here] Expressionopt ;

[no LineTerminator here]というものが気になる。これはなんだ。

If the phrase “[no LineTerminator here]” appears in the right-hand side of a production of the syntactic grammar, it indicates that the production is a restricted production: it may not be used if a LineTerminator occurs in the input stream at the indicated position. For example, the production:

ReturnStatement :
    return [no LineTerminator here] Expressionopt ;

indicates that the production may not be used if a LineTerminator occurs in the program between the return token and the Expression.

なるほど、return statementでは、returnとexpressionの間に、改行があってはならないらしい。いや、mayなので、改行があってもいいのだろう。ただし、expressionを省略したことになるだろうが。

そして、return statementのexpressionが省略された場合は、"If Expression is omitted, the return value is undefined."となるので、undefinedが返される。

ちなみに、セミコロンを省略してもよい理由については、本の虫: Javascriptで改行が特別な意味を持つケースを参照のこと。

JavascriptはC++より難しい。

でも、規格は、C++より読みやすいと思う。すぐに理解できた。

wtfjsに掲載されているコードは、どれも非常に興味深いので、Javascriptプログラマは、ぜひ一読しておくことをおすすめする。

追記:昔、入門用に買ったオライリーを引っ張り出してきたら、return文に改行を書くと、セミコロンが補われるから気をつけろと書いてあった。さすがオライリーだ。しかし、これは重要だ。とすると、およそJavascriptの入門書なら、必ず書いておくべきであり、すべてのJavascriptプログラマは、これを知っているべきである。知らなかったのは、ひょっとして私だけなのだろうか。Javascript、怖い言語だ。

2 comments:

nanto_vi said...

> いや、mayなので、改行があってもいいのだろう。

これはmay notの一部なので、「~してはいけない」という禁止の意だと思います。

> いやしかし、もしこれがBlockと解釈されているのなら、haha: "ha!"、は、文法エラーである。

これは本体が式文であるラベル付き文とみなされるので、文法エラーにはなりません。

江添亮 said...

>これはmay notの一部なので、「~してはいけない」という禁止の意だと思います。
いや、そういう意味ではなくて、may notなので「弱い」禁止なのだろうということです。
shall notとは違うということです。

>これは本体が式文であるラベル付き文とみなされるので、文法エラーにはなりません。
あ、なるほど。
やはりJavascriptは変態だ。