Function.prototypeを拡張して遅延実行を実現する

JavaScriptにおいて関数というのはFunctionオブジェクトで、他のビルトインオブジェクトと同様に、組み込みのメソッドがある。これがapplyとcallしかないのだけれど、こんな感じに使う。

func.apply(thisObj,arguments)
func.call(thisObj,arg1,arg2,arg3)

thisObjには、その関数内で「this」として使うオブジェクトを指定する。applyの第二引数はargumentsオブジェクトを指定する。配列か、現在実行中の関数のargumentsオブジェクトを丸ごと別の関数に引き渡せる。つまり引数の長さが良くわかってなくても使える。

callは代わりに
func.apply(thisObj,[arg1,arg2,arg3])
と書けるので、実はいらないんじゃないかと思う。

これらは多分、ふつうにJavaScriptを書く上では全然必要でないし、知らなければ知らないでまったく問題にはならない。リファレンスなんかを見ても、リファレンス的な解説のみで具体的な使い方は書いていないと思う。

有名なのは引数の束縛とかそういうやつなのだけれど
http://www.interq.or.jp/student/exeal/dss/ejs/1/4.html

正直、これを読んでもどういうメリットがあるのかいまいち良くわからなかった。
でも、知っていれば知っているなりの書き方がある。

で、具体的に作ったのがこれ。
Object.extend = function(destination, source) {
    for (property in source) {
        if(source.hasOwnProperty(property)){
            destination[property] = source[property];
        }
    }
    return destination;
}
Object.prototype.extend = function(object) {
    return Object.extend.apply(this, [this, object]);
}
Function.prototype.extend({
    later : function(ms){
        var self = this;
        var func = function(){
            var arg = func.arguments;
            var apply_to = this;
            var later_func = function(){
                self.apply(apply_to,arg)
            };
            setTimeout(later_func,ms);
        };
        return func;
    }
});

var func = function(v){alert(v)};

func.later(1000)("1秒後に警告");
func.later(2000)("2秒後に警告");
func.later(1000).later(2000)("3秒後に警告");

(function(v){alert(v);arguments.callee.later(1000)(v)}).later(1000)("1秒ごとに実行")


Function.prototypeを拡張して、laterメソッドを加えてやる。加えるというのは正確ではなく、func.laterが見つからなかった場合に、Function.prototype.laterが実行されるようになる。これだけで、いちいち無名関数作ってsetTimeoutなんて書かなくても、あらゆる関数を簡単に遅延実行させることが出来るようになる。

Object.extendは便利だから使いまくる方向で。でもprototypeはコピーしないように改造した。
何をするコードかというと、元の関数を「1秒後に実行する関数」を生成して、返ってきた関数に引数を渡して実行する。この例だと引数は一つだけれど、複数の引数を必要とする関数でも同様に可能だ。
「1秒後に実行」ではないので、生成された関数をさらに加工することが出来る。三番目は1秒後に実行される関数をさらに2秒遅らせて実行する。

4番目はこれでもいい。
var interval = 1000;
(function(v){alert(v);arguments.callee.later(interval)(v)}).later(interval)("1秒ごとに実行");


実行中にinterval = 3000とかやったら実行中に外から周期を変更できる。arguments.calleeは現在実行されている関数の参照を表していて、これを使うと再起処理なんかをするのに関数名を決めうちにしなくて良い。

とまあ、こんな具合。

----
追記
later(1000).apply(this,arg)とかが動くように、ちょいと直した。
1秒後に別のオブジェクトに変形するオブジェクトとか作れる。


WriteBacks

apply メソッド

apply メソッドの応用例としては、
prototype.js の bind メソッドと bindAsEventListner はどうでしょうか。
javascript で OOP をする際には、これらのメソッドはかなり便利です。
主に、ハンドラメソッドで this を使いたい場合に用います。

逆に OOP を使わない (this を多用しない) 場合、
apply メソッドの利用場面は限られるのかもしれません。

Posted by oro at 2005/07/31 (Sun) 12:20:05

[Web][Javascript][OOP]HTMLElement.prototypeを拡張してinnerTextを実装する

[http://la.ma.la/blog/diary_200507302354.htm:title=Function.prototypeを拡張して遅延実行を実現する]を参考に(というかほとんどパクり)、以下のようなテストコードを書いて実行してみたらうまくいった(Firefoxの場合)。 prototypeベースのオブジェクト指向って結構面白いな。 参考 [http://la.ma.la/blog/diary_200507302354.htm:title=最速インターフェース研究会 :: Fun ...

Posted by ヒビノキロク at 2005/08/11 (Thu) 07:00:50

こんなのもラク?遅延/繰返し/回数指定して function を複製する2

javascriptで。 ・ 指定回数繰り返しさせる関数 ・ true の間、延々と繰り返しさせる関数(カウンター付) を前回の、「遅延させるだけの関数」から作成します。 「3歩または5歩進んで止まる」を100回繰り返します。 ・ 指定回数繰り返しさせる関数 ・ 角度をずらす関..

Posted by Script雑感 at 2006/10/28 (Sat) 09:21:21

再帰λ...

最速インターフェース研究会 :: Function.prototypeを拡張して...

Posted by p0t at 2007/02/06 (Tue) 19:04:43

??京??陷

日本人是全世界最无耻的猪。??京??陷

Posted by qiuzhiqing at 2008/01/15 (Tue) 14:27:17
TrackBack ping me at
http://la.ma.la/blog/diary_200507302354.trackback
Post a comment

writeback message: Ready to post a comment.







spam yoke. nanimo ireruna.