web-dev-qa-db-ja.com

Javascriptのイベントリスナー呼び出しからオブジェクトのプロパティにアクセスする

以下では、Javascriptでオブジェクトを作成しています。コンストラクター内で、イベントリスナーを設定しています。問題は、イベントが発生すると、this.propが見つからず、undefinedが出力されることです。どうすればこれを解決できますか?

   var someObj = function someObj(){
       this.prop = 33;
        this.mouseMoving = function() { console.log(this.prop);}

        document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);

 }
22
Ronald

イベントハンドラーが呼び出されると、「this」は「someObj」オブジェクトを参照しなくなります。 「this」を、mouseMoving関数がキャプチャするローカル変数にキャプチャする必要があります。

_var someObj = function someObj(){
    this.prop = 33;
    var self = this;
    this.mouseMoving = function() { console.log(self.prop);}

    document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
_

「someObjはコンストラクターです。つまり、new someObj()として呼び出されることを目的としています。そうでない場合、「this」がグローバルスコープになります。

「this」キーワードは、他の言語と同じようには機能しないため、JavaScriptでは混乱する可能性があります。覚えておくべき重要なことは、関数が作成されたときではなく、呼び出し元のオブジェクトにバインドされていることです関数が呼び出されたとき

24
Matthew Crumley

Javascriptの組み込みFunction.prototype.bind()は、この目的を目的としています。
例えば:

var someObj = function someObj(){
       this.prop = 33;
        this.mouseMoving = function() { console.log(this.prop);}

        document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving.bind(this),true);

 }

Bindメソッドの詳細はこちら: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

それ以外の場合は、オブジェクトsomeObjの参照を要素に渡し、その参照を次の行で使用する必要があります。

console.log(this.referenceToObject.prop); //this references the DOM element in an event.

JavaScript:The Good Parts by Douglas Crockfordのセクション4.3から:

関数を呼び出すと、現在の関数の実行が一時停止され、制御とパラメーターが新しい関数に渡されます。宣言されたパラメーターに加えて、すべての関数は、thisとargumentsの2つの追加パラメーターを受け取ります。このパラメーターはオブジェクト指向プログラミングで非常に重要であり、その値は呼び出しパターンによって決定されます。 JavaScriptの呼び出しには、メソッド呼び出しパターン、関数呼び出しパターン、コンストラクター呼び出しパターン、および適用呼び出しパターンの4つのパターンがあります。パターンは、これが初期化されるボーナスパラメータの方法が異なります。

Crockfordは、次のように、これらの各パターンでの「this」のバインドについて引き続き説明します。

メソッド呼び出しパターン:関数がオブジェクトのプロパティとして格納されている場合、それをメソッドと呼びます。メソッドが呼び出されると、これはそのオブジェクトにバインドされます。

関数呼び出しパターン:このパターンで関数が呼び出されると、これはグローバルオブジェクトにバインドされます。これは言語の設計の間違いでした。

コンストラクター呼び出しパターン:関数が新しいプレフィックスで呼び出されると、関数のプロトタイプメンバーの値への非表示のリンクを使用して新しいオブジェクトが作成され、これがその新しいオブジェクトにバインドされますオブジェクト。

Apply Invocation Pattern: applyメソッドを使用すると、関数の呼び出しに使用する引数の配列を作成できます。また、これの値を選択することもできます。 applyメソッドは2つのパラメーターを取ります。 1つ目は、これにバインドする必要がある値です。 2つ目は、パラメーターの配列です。

5
Vijay Dev

まず、JavaScriptで「これ」がどのように機能するかを理解する必要があります。 'this'キーワードは、C#やJavaなどの他の言語での動作とは異なります。詳細については、次の投稿をお読みください。

JavaScriptでの「this」キーワードの動作の理論的根拠は何ですか?

Matthewがコードで概説しているように、それを理解したら、「this」への参照を保存して、mouseMoving関数内でその参照を使用できます。

全体としては、これらの問題を処理するJavaScriptフレームワーク(jQuery、YUI、MooToolsなど)を使用することをお勧めします。例えば。 Internet Explorerでは、addEventListenrではなくaddEventを使用してイベントを添付します。

3
SolutionYogi

'me'という名前の変数を使用して、グローバルJavaScript変数 'self'との競合を回避できます。

function someObj() {
  var me = this;
  this.prop = 33;

  this.mouseMoving = function() {
    alert(me.prop);
  }

  document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
3
alexbuzzbee

関数宣言にいくつかのタイプミスがあります。

Prop変数は、 "public"または "visible"としても定義されます。 )メンバー(this.propを使用)、そうすることで、外部関数からのthisの参照(実際にはオブジェクトインスタンス)、関数の "private"メンバーとして(varを使用)、作成されたオブジェクトのインスタンスにアクセスし、 "public" propメンバー。

このコードを書き直すには、いくつかの選択肢があります。

function someObj (){
    var self = this;
    this.prop = 33;
    this.mouseMoving = function() { alert(self.prop);} // You access the current
                                                       // instance, stored in *self*
                                                       // since *this*, inside the 
                                                       // function, is in another 
                                                       // context.
    //...
}

var mySomeObj = new someObj(); // Object instantiation

または、次のことができます。

function someObj (){
    var prop = 33;
    this.mouseMoving = function() { alert(prop);} 

    //...
}
var mySomeObj = new someObj(); // Object instantiation

varで宣言された変数は、主要なコンストラクター関数内で宣言された関数にアクセスできます。この機能は Closures として知られています。 。

0
CMS