web-dev-qa-db-ja.com

var self = this?

インスタンスメソッドをイベントハンドラーのコールバックとして使用すると、thisのスコープが"My instance"から"コールバックと呼ばれるものすべて"に変更されます。だから私のコードは次のようになります

function MyObject() {
  this.doSomething = function() {
    ...
  }

  var self = this
  $('#foobar').bind('click', function(){
    self.doSomethng()
    // this.doSomething() would not work here
  })
}

動作しますが、それが最善の方法ですか?私には奇妙に見えます。

180
defnull

この質問はjQueryに固有のものではなく、JavaScript全般に固有のものです。中心的な問題は、組み込み関数で変数を「チャネル化」する方法です。これは例です:

var abc = 1; // we want to use this variable in embedded functions

function xyz(){
  console.log(abc); // it is available here!
  function qwe(){
    console.log(abc); // it is available here too!
  }
  ...
};

この手法は、クロージャーの使用に依存しています。ただし、thisはスコープごとに動的に変化する可能性がある擬似変数であるため、thisでは機能しません。

// we want to use "this" variable in embedded functions

function xyz(){
  // "this" is different here!
  console.log(this); // not what we wanted!
  function qwe(){
    // "this" is different here too!
    console.log(this); // not what we wanted!
  }
  ...
};

私たちは何ができる?それをいくつかの変数に割り当て、エイリアスを介して使用します。

var abc = this; // we want to use this variable in embedded functions

function xyz(){
  // "this" is different here! --- but we don't care!
  console.log(abc); // now it is the right object!
  function qwe(){
    // "this" is different here too! --- but we don't care!
    console.log(abc); // it is the right object here too!
  }
  ...
};

thisは、この点で一意ではありません。argumentsは、エイリアスによって同じ方法で処理する必要がある他の擬似変数です。

205
Eugene Lazutkin

ええ、これは一般的な標準のようです。一部のコーダーは自己を使用し、他のコーダーは私を使用します。イベントではなく、「実際の」オブジェクトへの参照として使用されます。

実際に取得するのに少し時間がかかりましたが、最初は奇妙に見えます。

私は通常、これを私のオブジェクトの一番上で行います(私のデモコードを言い訳-それは他の何よりも概念的であり、優れたコーディング技術に関するレッスンではありません):

function MyObject(){
  var me = this;

  //Events
  Click = onClick; //Allows user to override onClick event with their own

  //Event Handlers
  onClick = function(args){
    me.MyProperty = args; //Reference me, referencing this refers to onClick
    ...
    //Do other stuff
  }
}
17
BenAlabaster

ES2015を実行している場合、またはタイプスクリプトとES5を実行している場合は、コード内で矢印関数を使用できます。そのエラーに直面することはなく、これはインスタンス内の目的のスコープを参照します。

this.name = 'test'
myObject.doSomething(data => {
  console.log(this.name)  // this should print out 'test'
});
12
Aran Dekar
var functionX = function() {
  var self = this;
  var functionY = function(y) {
    // If we call "this" in here, we get a reference to functionY,
    // but if we call "self" (defined earlier), we get a reference to function X.
  }
}

編集:オブジェクトにもかかわらず、ネストされた関数は、周囲のオブジェクトではなく、グローバルウィンドウオブジェクトを引き受けます。

10
serkan

これに対する1つの解決策は、javascriptのbindメソッドを使用して、すべてのコールバックをオブジェクトにバインドすることです。

名前付きメソッドを使用してこれを行うことができますが、

function MyNamedMethod() {
  // You can now call methods on "this" here 
}

doCallBack(MyNamedMethod.bind(this)); 

または匿名のコールバックを使用して

doCallBack(function () {
  // You can now call methods on "this" here
}.bind(this));

var self = thisに頼る代わりにこれらを行うと、thisのバインディングがjavascriptでどのように動作し、クロージャー参照に依存しないかを理解できます。

また、ES6の太い矢印演算子は、基本的に匿名関数の呼び出し.bind(this)と同じです。

doCallback( () => {
  // You can reference "this" here now
});
4
Bart Dorsey

JQueryは使用していませんが、Prototypeのようなライブラリでは、関数を特定のスコープにバインドできます。そのため、コードは次のようになります。

 $('#foobar').ready('click', this.doSomething.bind(this));

Bindメソッドは、指定したスコープで元のメソッドを呼び出す新しい関数を返します。

3
neonski

これに追加するのは、ES6では 矢印関数 であるため、this値をキャプチャするため、これを行う必要はありません。

2
aug

実際、doSomething関数内で何をするかによって決まると思います。このキーワードを使用してMyObjectプロパティにアクセスする場合は、それを使用する必要があります。ただし、object(MyObject)プロパティを使用して特別なことをしていない場合は、次のコードフラグメントも機能すると思います。

function doSomething(){
  .........
}

$("#foobar").ready('click', function(){

});
1
Milinda