Search on the blog

2013年1月20日日曜日

setTimeoutでクロージャ使うときのメモ

毎回悩んでるような気がするので、メモしておく。

やりたいこと
以下のような処理をタイマーを使って実行したい。
for (i = 0; i < 5; i++)
    alert(i);

ダメな例
「0, 1, 2, 3, 4」と1秒間隔でアラートが出ると期待してしまいそうですが、「5, 5, 5, 5, 5」と出ます。「へ〜せいポリスメン!!」じゃありませんよ。
millisec = 0;
for (i = 0; i < 5; i++) {
    millisec += 1000;
    setTimeout(function(){alert(i);}, millisec);
}

クロージャを使ってみる
上のソースがうまくいかなかったのは、関数が実行されるときには既にforループは完了してしまっていてi=5となっているからです。iの値を"クローズド"してあげるとうまくいきます。
function genFunc(x) {
    return function() {
        alert(x);
    }
}
millisec = 0;
for (i = 0; i < 5; i++) {
    millisec += 1000;
    setTimeout(genFunc(i), millisec);
}

無名関数を使ってみる
わざわざクロージャ用の関数を定義するのは面倒くさいような気がするので、無名関数で書いてみます。
millisec = 0;
for (i = 0; i < 5; i++) {
    millisec += 1000;
    setTimeout(function(x) {
        return function() {
            alert(x);
        }
    }(i), millisec);
}
なんか分かりにくいな。。クロージャをグローバルスコープに書きたくないというのであれば、下のような書き方の方が可読性も若干高くていいかもしれない気がします。(が、どっちがいいのかは分かりません。)
一般的には書くんですかねー?javascript詳しい人教えてください。
millisec = 0;
for (i = 0; i < 5; i++) {
    millisec += 1000;
    genFunc = function(x) {
        return function() {
            alert(x);
        }
    };
    setTimeout(genFunc(i), millisec);
}

0 件のコメント:

コメントを投稿