1

私はJSが初めてで、関数が「クラスのような」構造を宣言する方法であることを理解しています。私はこのようなことをしようとしています:

function Game() {
  // Class stuff

  this.handleClick = function(e) {
    alert(e);
  }

  // Bind event to method previously defined
  $('#board').bind('click', function(e) {
    this.handleClick(e);              // <--- THIS IS THE PROBLEMATIC LINE
  });
}

さて、「問題のある行」に私が書いた場合:

  handleClick(e)

私は得るUncaught ReferenceError: handleClick is not defined

代わりに、私が書くと:

  this.handleClick(e);

私は得るUncaught TypeError: Object #<HTMLCanvasElement> has no method 'handleClick'

しかし、もしそうなら:

function Game() {
  // Class stuff

  this.handleClick = function(e) {
    alert(e);
  }

  var game = this;                    // <--- I ASSIGN this TO board
  // Bind event to method previously defined
  $('#board').bind('click', function(e) {
    game.handleClick(e);              // <--- THIS WORKS!! WHY????
  });
}

できます!?!?!

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

  1. どうしてこうなってしまうのでしょうか?問題になる可能性があることはわかってthisいますが、変数に代入するとそのように変化するのはなぜですか?
  2. 私はこれを間違っていますか?このようなことをよりエレガントな方法で達成するためのより良い方法はありますか?
4

1 に答える 1

4

Javascript のクロージャの実装に 1 つの穴が見つかりました。(クロージャが何であるかを知らなくても、心配する必要はありません。)

thisJavascript では、関数が呼び出されたオブジェクトを参照します。したがって、たまたま関数の値が割り当てられたプロパティを持つオブジェクトがあり、そのプロパティを呼び出すと、thisポインターはオブジェクトを参照します。this関数が作成された場所を参照したり、関数自体を参照したりすることはありません。

var object = {};
object.myfunc = function() { console.log(this); } //<-- this will refer to object
object.myfunc();

イベント ハンドラーの場合、ハンドラー関数 (純粋な Javascript では、jQuery を無視する) が DOM 要素に割り当てられるため、その要素から呼び出されthis、DOM 要素を指します。

上記の例のように、ローカル変数を使用するgameと、作成した関数 (「クロージャー」) がその変数を「閉じ」、関数が定義された場所でスコープ内の変数の値をキャプチャすることを意味します。を除く 任意の変数this。したがって、回避策はこれを処理するための非常に一般的な方法です。

これを処理するもう 1 つの一般的な方法は、Underscore.js のようなライブラリを使用することです。このライブラリには、bind高階関数の魔法を実行する関数が呼び出され、this常に必要なものを指していることを確認します。

$('board').bind('click', _.bind(function(e) {
  this.handleClick(e);
}, this));

このため、Underscore.js は (jQuery に次ぐ) 私のお気に入りの Javascript ライブラリの 1 つであり、バインド関数にほぼ独占的に使用しています。

于 2013-06-26T03:31:25.780 に答える