Mach3.laBlog

Prototype.jsのbind的なノリのものを書く

この記事は賞味期限切れです。(更新から1年が経過しています)

この記事の情報は古くなっています。
$.proxyを利用するか、Function.prototype.bind (あるいはそのpolyfill)を利用しましょう。

最近でこそjQueryを利用する機会が増えて来ましたが、
以前はよくPrototype.jsを好んで利用していました。
その最も大きな理由としてbind/bindAsEventListenerの存在があります。
Prototype API documentation | Function class

要するにfunctionのスコープをあるオブジェクトに固定したい場合に使うのですが、
イベントハンドラに登録する時なんかに結構重宝します。
でもコレだけのためにPrototype.jsに限定されちゃうのもアレなので
似たような動作をする拡張を書いてみました。

Function.prototype.scope = function(target,arg){
    var _func = this;
    return function(){
        var args = [];
        for(i=0;i<arguments.length;i++){ args.push(arguments[i]); }
        if(arg!=undefined){ args.push(arg); }
        _func.apply(target,args);
    }
}

「bind」だとjQuery使った時に競合してしまうので「scope」で。
こんな感じにして使います。

MyObject.mymethod.scope( MyObject, argument );

argumentで渡した値は、イベントハンドラの最後の引数として受け取れます。
通常のイベントならば第一引数にイベントオブジェクトを渡されるので、第二引数。
複数の引数を渡してくるような特殊なイベントの場合は、第三以降の引数になります。

以下、簡単な例など。
※イベント登録にjQueryを使ってますのでご了承を。

1.単純に登録だけする例

var Test = {
    name:"TestObj",
    click:function(e){
        alert(this.name); // "TestObj"
        alert(e.type); // "click"
    }
};
$("#testButton1").bind("click",Test.click.scope(Test));

従来通り、引数でイベントオブジェクトを受け取れます。

2. 引数と一緒に登録する例

var Test2 = {
    name:"TestObj2",
    click:function(e,value){
        alert(this.name); // "TestObj2"
        alert(e.type); // "click"
        alert(value); // "hogehoge"
    }
};
$("#testButton2").bind("click",Test2.click.scope(Test2, "hogehoge"));

第一引数でイベントオブジェクトを、第二引数でscopeで渡した値を受け取れます。

3. 複数の引数を渡してくるイベントの例

var Test3 = {
    name:"TestObj3",
    onSuccess:function(data,status,value){
        alert(this.name); // "TestObj3"
        alert(data); // test.txt内のコンテンツ
        alert(status); // "success"
        alert(value); // value
    }
};
$.ajax({
    url:"test.txt",
    method:"GET",
    success:Test3.onSuccess.scope(Test3,"hogehoge")
});

jQuery.ajaxはsuccessに登録したコールバックに、
ファイルの内容と、通信のステータスの二種類の引数を渡します。
その場合、scopeで渡した第二引数は
コールバックでは第三引数で受け取る事が出来ます。

jQuery.ajax() – jQuery API

success(data, textStatus, XMLHttpRequest)
A function to be called if the request succeeds. The function gets passed three arguments: The data returned from the server, formatted according to the ‘dataType’ parameter; a string describing the status; and the XMLHttpRequest object (available as of jQuery 1.4). This is an Ajax Event.

もっとも、jQuery.ajax の場合はコールバック内のthisで
jQuery.ajaxのオプションを呼び出す事ができるので
スコープをいじらずに普通に登録したほうが有用に思えます。
あくまで複数の引数を渡された時の例、という事で。

4. ややこしいから普通に書きたいんだが?

上で紹介している様な手法はソースの見通しがよくなるというメリットがありますが
そもそもapply/call自体がそういう役割を持っているメソッドなのでそれをそのまま使えば良いとも言えます。

var Test4 = {
    name:"TestObj4",
    click:function(e,value){
        alert(this.name); // "TestObj4"
        alert(e.type); // "click"
        alert(value); // "hogehoge"
    }
};
$("#testButton3").bind("click",function(e){
    Test4.click.apply(Test4, [e,"hogehoge"]);
});

複数以上の引数を渡したい場合はarrayを受け取れるapplyを使いますが、
渡したい値がひとつだけの場合はcallでも良いですね。

Test4.click.call(Test4, e);

以上ながくなりましたが、apply/callの使い方が学べたのは収穫でした。
参考にしたのはこちら。 JavaScript call and apply – Trephine


2010/04/20
フォロー記事書きました
いつの間に実装されていたjQuery.proxy等という便利な機能

コメント

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です


*