JavaScript の落とし穴

ここ2週間ほど JavaScript を使ってるわけですが、いくつか嵌った部分があったのでメモ。

変数の宣言

var s = 'Hello, world';
(function() {
    print(s);
    var s = 'Hello, function';
    print(s);
})();

結果

undefined
Hello, function

これはサイ本の例。実際に似たようなコード書いて悲しいことになりました。
同じ関数内のどこで宣言されても、全部関数の先頭で宣言されたのと同じ意味になるらしいので怖いですね。

bool への暗黙変換

var Obj = function() {
  var value;

  this.setValue = function(v) {
    // 値が設定されていて、変更が無いなら何もしない
    if (value && v == value) return;

    // ここで何か処理する

    print(value + ' to ' + v);
    value = v;
  }
}

var obj = new Obj();
obj.setValue(0);
obj.setValue(0);
obj.setValue(1);
obj.setValue(1);

結果

undefined to 0
0 to 0             // あ、あれ?
0 to 1

まあ何ていうか、気付けよって感じですが。
一応解説しておくと、if (value) ってやったとき、value が undefined の時は当然 false なのですが、value が 0 のときも false と判断されちゃうことを忘れてたっていう。
boost::optional 的な考え方をしていたんだけど、それは危険ですよと。


余談だけど、これ、

if (value && v == value) return;

の部分を

if (value != undefined && v == value) return;
if (value != null && v == value) return;
if (value !== undefined && v == value) return;

あたりにするのが正しいと思うんだけど、じゃあこの中でどれがいいのよって迷ってしまったっていう。
結局、何となくで value != undefined にしました。

セミコロン省略

var f = function() {
    return function() { print('hoge'); }
}

(function() {
    print('fuga');
})();

結果

hoge

よく見たら当然なんだけれども、しばらく気がつきませんでした。
f に代入してる部分は、関数式を使った単なるステートメントなので、文末にセミコロンが必要(なこともある)っていう。


ということでこの例は、最初の関数を定義すると同時に fuga を出力する関数を引数に渡して最初の関数を呼び出すけれども、その引数は無視され、最初の関数は hoge を返す関数を返し、その hoge を返す関数を呼ぶというものになります。


残念な挙動に悩まされないためにも、関数式を含めた文を書くときでもめんどくさがらずにセミコロンを書きましょう、といいたいけど、} の後ろにセミコロン打つのってすごい違和感があるので、まあ問題が出たときにこの辺疑えばいいんじゃねって気がしなくも。

使ってみた感想

まだ 2 週間しか使ってないけれども、JavaScript はすっごいコードが書きやすい(特にクロージャ周り)ので、ゲーム開発でも JavaScript 使いたいですね。