ぶれすとつーる

だいたいjavascript

関数の再代入時のthis

オブジェクトのプロパティメソッドを一旦変数に代入してやるとthisの所在がかわってしまうのでそれについて

(function(){
    var obj = {
        hoge: 'abc',
        moge : function() {
            console.log(this.hoge);
        }
    };
   
    obj.moge(); // abc
}());

普通にオブジェクトのプロパティを実行する分には問題なし
実行時にmogeメソッドのthisはobjをさしてるから


次に、オブジェクトのプロパティメソッドを変数に再代入する

(function(){
    var obj = {
        hoge: 'abc',
        moge : function() {
            console.log(this.hoge);
        }
    };

    var method = obj.moge;
    method(); // undefined
}());

これはNG
なぜなら method = obj.moge の代入処理時にthisの値が = の左辺になってしまってうから
代入実行時にmethodはオブジェクトではないのでthisはグローバルをさしてしまう


というわけでthisを束縛してあげるproxy関数を作って間に一枚かますとok

(function(){
    var obj = {
        hoge: 'abc',
        moge : function() {
            console.log(this.hoge);
        }
    };

    function proxy(fn, obj){
        return function(){
            return fn.call(obj);
        }
    }

    var method = proxy(obj.moge, obj);
    method(); // abc
}());

これならproxyのおかげでthisとしてobjを束縛してるのでok


引数とれないと色々不都合あるので引数とれるようにしてあげる。

(function(){
    var obj = {
        hoge: 'abc',
        moge : function(a, b, c, d) {
            console.log(this.hoge);
            console.log([a, b, c, d]);
        }
    };

    function proxy(fn, obj){
        return function(/* arguments */){
            var args = Array.prototype.slice.call(arguments);
            return fn.apply(obj, args);
        }
    }

    var method = proxy(obj.moge, obj);
    method(1, 2, 3, 4); // abc , [1,2,3,4]
}());

これで大体の場合はok

追記


@nazomikan var method = obj.moge.bind(obj) で OK だったり...

teramako先生からご指摘をいただきました!
新しいブラウザならjavascript1.8.5からFunction.prototype.bindが追加されているのでそれを利用するといいです。

(function(){
    var obj = {
        hoge: 'abc',
        moge : function(a, b, c, d) {
            console.log(this.hoge);
            console.log([a, b, c, d]);
        }
    };

    var method = obj.moge.bind(obj);
    method(1, 2, 3, 4); // abc , [1,2,3,4]
}());

ちなみにこれはff4, ie9, chrome7,opera11.6以降から使えます
ご指摘ありがとうございました><