1

prototype今日、Javascriptとthisリファレンスを使用して非常に奇妙な問題に遭遇しました。

基本的に、私は2つのオブジェクトを持っています。1つのオブジェクトがdiv要素を利用し、.onclickにイベントを登録できるようにしdivます。他のオブジェクトはこの機能をonclick利用し、最初のオブジェクトを使用してイベントを登録します。

コードは次のとおりです。

の世話をする私の最初のオブジェクトdiv

DivObject = function() {};
DivObject.prototype.setClickListener = function(clickListener){
    document.getElementById("myDiv").onclick = function(e){
        clickListener(e);
    };
};

私の 2 番目のオブジェクトは、この機能を使用します。

MainObject = function(){
    this.myString = "Teststring";
    this.divObj = new DivObject();
    this.divObj.setClickListener(this.handleClick);
};

MainObject.prototype.handleClick = function(e){
    // do something with e
};

問題は、内部MainObject.prototype.handleClickでは、this参照がwindowではなくオブジェクトを参照していることMainObjectです。したがって、console.log(this)この関数内でログが記録され[Object window]ます。

この動作は jsfiddle で確認できます。

setClickListener回避策として、次のように関数を使用します。

var thisRef = this;
this.divObj.setClickListener(function(e){
    thisRef.handleClick(e);
});

これで、関数内のthis参照は myを参照します(私が望むように)。handleClickMainObject

jsfiddle でこの回避策を参照してください。

私の質問は次のとおりです。

参照が 1 回はオブジェクトをthis参照し、もう 1 回はオブジェクトの参照を参照するのはなぜですか? どこかでオーバーライドされていますか?私はいつも自分のオブジェクトで使用すると思っていましたが、それが本当に自分のオブジェクトの参照であると確信できますか? 私が現在使用している回避策は、この問題を解決する方法ですか、それともこのケースを処理するための他のより良い方法はありますか?windowthisthisthis

4

2 に答える 2

1

.bind()を使用してこれを修正できます:

this.divObj.setClickListener(this.handleClick.bind(this));

デモをご覧ください。

于 2012-10-03T06:12:38.613 に答える
1

あなたの質問:

this 参照が 1 回は window オブジェクトを参照し、もう 1 回はオブジェクトの this 参照を参照するのはなぜですか?

bindを使用する以外に、関数の値は関数のthis呼び出し方法によって設定されます。あなたがするとき:

this.divObj.setClickListener(this.handleClick);

関数参照を割り当てているため、関数は修飾なしで後で呼び出されます (つまり、 this.handleClick ではなく、単に handleClick として呼び出さます)。関数に入ると、呼び出しによって設定されないため、デフォルトでグローバル (ウィンドウ) オブジェクトになるか、厳密モードでは未定義のままになります。this

どこかでオーバーライドされていますか?

いいえ、this実行コンテキストに入ると値が設定されます。上書きしたり、直接割り当てたりすることはできません。呼び出しでのみ設定できます(たとえば、newapplycallを使用してオブジェクトのメソッドとして)またはbindを使用して(また、アロー関数はそれらを囲むのthisを採用します)レキシカル実行コンテキスト)。

オブジェクトで this を使用すると、それが実際にオブジェクトの this 参照であると確信できますか?

あなたが割り当てを行う時点で、thisあなたが期待するものです。ただし、関数を呼び出すのではなく、関数への参照を割り当てているため、そのthis時点では設定されませんが、後で呼び出されたときに設定されます。

私が現在使用している回避策は、この問題を解決する方法ですか、それともこのケースを処理するための他のより良い方法はありますか?

あなたの回避策は問題ありません(そして一般的な修正です)。クロージャーが作成されるため、メモリに軽微な影響が生じる可能性がありますが、深刻なことはありません。非常に古いバージョンの IE では、DOM オブジェクトに関係する循環参照が原因でメモリ リークが発生していましたが、これは修正されています。

bindソリューションは、明確さとメンテナンスの観点からおそらく優れています。bindのサポートが組み込まれていないブラウザには、忘れずに「モンキー パッチ」を含めてください。

SO にコードを投稿してください。他の場所に投稿されたコードに引き続きアクセスできるという保証はありません。コードの回避策:

MainObject = function(){
    this.myString = "Teststring";
    this.divObj = new DivObject();
    var thisRef = this;
    this.divObj.setClickListener(function(e){
        thisRef.handleClick(e);
    });
};
于 2012-10-03T06:41:38.457 に答える