もっとエレガントにsetTimeoutをメソッド化する方法

※追記:あまりにも記事タイトルが適当すぎて我ながら日本語でおkと思ったのでタイトルを変えました。

http://labs.cybozu.co.jp/blog/kazuho/archives/2006/12/oo-settimeout.php
http://blog.livedoor.jp/dankogai/archives/50714622.html

このネタはmalaさんが1年半前に通過した地点なのである程度常識の部類かと思ってました。

でもdankogaiがわざわざやるってことは知らない人も多そうだし、malaさんが同じネタをまたやるようにも思えないので、ついでにLDRに現在使われてるFunction.prototype.laterとかを紹介してみる。

Function.prototype.later = function(ms){
  var self = this;
  return function(){
    var args = arguments;
    var thisObject = this;
    var res = {
      complete: false,
      cancel: function(){clearTimeout(PID);},
      notify: function(){clearTimeout(PID);later_func()}
    };
    var later_func = function(){
      self.apply(thisObject,args);
      res.complete = true;
    };
    var PID = setTimeout(later_func,ms);
    return res;
  };
};

later()の戻り値で、中断とか即実行とかを処理するオブジェクトを返してます。
dankogaiのやり方だとオブジェクトのtimeoutプロパティを汚染しちゃうけど、こちらのやり方はsetTimeout()の戻り値をクロージャ内で処理していて汚染が少ないのがエレガント。

使うときはこんな感じ

function example(msg){
  alert(msg);
}

//〜〜〜

//遅延実行
var task = example.later(1000)('hello');

//〜〜〜

//キャンセル
task.cancel();

//〜〜〜

//まだ実行してなかったら、やっぱり即実行
if(!task.complete){
  task.notify();
}

キャンセルとか即実行とか終了確認が必要なければlater()の戻り値を無視するだけ。
人様の書いたソースの解説でちょっと申し訳ないですが、LDRのソースはこの手のイディオムの宝庫なので読むと勉強になりますよ、と。