var self = this?


182

イベントハンドラのコールバックがの範囲に変更とインスタンスメソッドを使用してthisから、「マイインスタンス」「ただのコールバックと呼ばれるものは何でもします」。だから私のコードはこのようになります

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

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

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


15
オブジェクトselfがあるので避けてwindow.selfください。独自のselfvar を宣言し忘れた場合(たとえば、コードを移動するときなど)、誤ってそれを使用してしまう可能性があります。これは、見つけたりデバッグしたりするのが面倒です。のようなものを使用することをお勧めします_this
Alastair Maw 2014


3
JavaScriptのチュートリアル:「の値はthis。JavaScriptで動的な機能がされたときに決定されると呼ばれ、それが宣言されたときに、ではありません。」
DavidRR 2015年


事は、グローバルスコープでself === thisです。したがって、selfローカルコンテキストでは意味があり、パターンに従います。
programmer5000

回答:


210

この質問は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。エイリアスによって、同じように処理する必要がある他の疑似変数です。


7
「this」を関数呼び出しにバインドし、それを渡したり、変数スコープを横断したりしないでください
マイケル

10
@michaelどうして?
クリスアンダーソン

@michaelパイプ、マップ、サブスクライブ内で作業している可能性があります... 1つの関数で関数を呼び出さず、この場合は「this」が変更されるため、変数スコープが解決策です
Skander Jenhani

@SkanderJenhaniそのコメントは8歳です。今日の私の答えは大きく異なります
マイケル

18

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

それは本当に得るのに少し時間がかかったものですが、最初は奇妙に見えます。

私は通常、これをオブジェクトの一番上で実行します(デモコードを許してください。これは他の何よりも概念的であり、優れたコーディング手法のレッスンではありません)。

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
  }
}

12
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.
  }
}

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


あなたは何をvar self = thisしているのかを説明しているようですが、それは質問が求めていることではありません(質問はそれが問題の最善の解決策であるかどうかを尋ねています)。
クエンティン2015

3
「中心的な問題は、組み込み関数で変数を「チャネル化」する方法です。」承認された回答でこの声明に同意します。その上、「その」実践には何の問題もありません。それはかなり一般的です。したがって、「コードが私には奇妙に見える」部分への回答として、私はそれがどのように機能するかを説明することを選択しました。「コードが私には奇妙に見える」理由は、それがどのように機能するかの混乱から来ていると思います。
serkan

12

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

this.name = 'test'
myObject.doSomething(data => {
  console.log(this.name)  // this should print out 'test'
});

5
説明として:ES2015では、矢印関数thisは定義範囲からキャプチャします。通常の関数定義はそれを行いません。
defnull 2016

@defnull特別なことではないと思います。関数はブロックスコープを作成します。そのため、関数の代わりに矢印表記を使用すると、スコープを作成できなくなります。そのため、これは依然としてこのthis変数の外側を参照します。
Nimeshka Srimal 2017

4

これに対する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
});

個人的に私は.bind(this)がよりタイピングされていると思います。thisへの参照を私(または何でも)に変更し、それを使用するだけでコードがよりクリーンになります。ファットアローは未来のトーです。
davidbuttar

3

私はjQueryを使用していませんが、Prototypeなどのライブラリでは、特定のスコープに関数をバインドできます。そのことを念頭に置くと、コードは次のようになります。

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

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


に似ています:$('#foobar').ready('click', this.doSomething.call(this));そうですか?
Muers、

このbindメソッドは古いブラウザでは機能しないため、$.proxy代わりにこのメソッドを使用してください。
グッファ

2

これにES6で追加したのは、矢印関数のため、this値を取得するため、これを実行する必要はありません。


1

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

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

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

});
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.