1

JavaScriptでクラスを定義し始めていますが、キーワードで多くの問題が発生していthisます。

これが私がやりたいことの例です:

function MyMap() {

    this.map = new google.maps.Map(....);

    google.maps.event.addListener(this.map, 'idle', function() {
        this.mapIdle();    // PROBLEM: "this" undefined
    });

    this.mapIdle = function() {
        google.maps.event.addListener(marker, 'click', function() {
            $("button").click(function() {
                $.ajax({
                    success: function() {
                        this.map.clearInfoWindows(); // PROBLEM: "this" undefined
                    }
                });
            });
        });
    }
}

コメントでわかるように、クロージャー内thisで使用されているため、ここでは機能しません。

私は次のような回避策を使い始めました:

var that = this;
google.maps.event.addListener(this.map, 'idle', function() {
    that.mapIdle();
});

または、コールバック関数の周りにコールバック関数を定義する必要がある場合でも(真剣に!!)。

これは非常に醜く、どこでも機能するわけではありません。ネストされたラムダ関数をたくさん取得すると(私が示した例のように)、クラス属性の使用方法がわかりません。

それを行うための最良かつ最も正しい方法は何ですか?

4

4 に答える 4

3

最も簡単な方法は、すでに述べたように変数を定義することselfです(またはthat、非セマンティック変数名を気にしない場合は)。

function MyMap() {
   var self = this;

   // in nested functions use self for the current instance of MyMap
}

プロトタイプに追加するメソッドに対して再度実行する必要があることに注意してください(ネストされた関数を使用する場合)。

MyMap.prototype.myMethod = function() {
   var self = this;
   // use self in nested functions
};

IE <= 8では機能しないことに注意して、.bind()メソッドについても確認する必要があります。

コールバックの周りにコールバックを定義することについてリンクした質問は、別の問題を解決することです。つまり、ループ内にネストされた関数が適切なループカウンター値にアクセスできるように適切なクロージャ構造を設定します。それは問題とは何の関係もありませんthisself(そして、必要に応じてテクニックと簡単に組み合わせることができます。)

于 2012-04-03T22:22:18.710 に答える
1

jQueryを使用している場合は、次の場合に$.proxy便利です。

http://api.jquery.com/jQuery.proxy/

于 2012-04-03T22:08:29.173 に答える
1

オブジェクトと関数をローカル変数に割り当てるだけで、それらはコールバック関数のクロージャに含まれます。

function MyMap() {

  var map = new google.maps.Map(....);

  var mapIdle = function() {
    google.maps.event.addListener(marker, 'click', function() {
      $("button").click(function() {
        $.ajax({
          success: function() {
            map.clearInfoWindows();
          }
        });
      });
    });
  };

  this.map = map;
  this.mapIdle = mapIdle; // Is this needed?

  google.maps.event.addListener(this.map, 'idle', function() {
    mapIdle();
  });

}
于 2012-04-03T22:12:35.023 に答える
1

JavaScriptでは、this関数呼び出しごとに再割り当てされます。

これは、JavaScriptで注意する必要があることです。最初は混乱するかもしれませんが、いくつかの簡単なルールを知ったら、実際にはかなり簡単です。

のようなメソッド呼び出しの場合myObj.doSomething()thisは自動的にmyObjの内部に設定されdoSomething()ます。

this関数呼び出しを行うときにの値を明示的に制御する場合は、doSomething.apply()またはを使用して、関数内で設定されるdoSomething.call()ものを制御できます。thisこれが、イベントハンドラーのコールバックが行うことです。thisそれらは、イベントを作成したオブジェクト(非常に便利なもの)を指すように明示的に設定されています。.apply()MDNについて、およびMDNについて詳しく読むことができます.call()

通常の関数を呼び出すだけthisで、ブラウザではオブジェクトであるグローバルオブジェクトに設定されwindowます。

すべての関数呼び出しが変更されるため、すべてのコールバック関数の値がthis混乱しますthis。Ajax関数では、イベントハンドラーはコールバックであり、成功ハンドラーはコールバックであるため、の値がthis周囲のコードから保持されないことを期待する必要があります。thisプロキシまたはバインド関数を使用した回避策がありますが、通常は、クロージャ内の以前の値をキャプチャし、そこから。のようなものを使用してアクセスするのと同じくらい簡単var self = this;です。

あなたの状況では、イベントハンドラーの外部からポインターにアクセスしたい場合this、正しいことは、イベントハンドラーまたはイベント内のAjax呼び出しでさえアクセスできるローカル変数にポインターを保存することです。ハンドラ。それを行うためのよりクリーンな方法はありません。thisこのようにして、イベントまたはAjax呼び出しからのthisポインターと、呼び出し元オブジェクトからのポインターの両方に次のようにアクセスできます。

    var self = this;
    self.mapIdle = function() {
        google.maps.event.addListener(marker, 'click', function() {
            $("button").click(function() {
                $.ajax({
                    success: function() {
                        self.map.clearInfoWindows(); // PROBLEM: "this" undefined
                    }
                });
            });
        });
    }
}
于 2012-04-03T23:56:03.493 に答える