知っておくべきこと this
this
(別名「コンテキスト」)は、各関数内の特別なキーワードであり、その値は、関数が呼び出された方法にのみ依存し、定義された方法/時期/場所には依存しません。他の変数のような字句スコープの影響を受けません(矢印関数を除く、以下を参照)。ここではいくつかの例を示します。
function foo() {
console.log(this);
}
// normal function call
foo(); // `this` will refer to `window`
// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`
// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`
詳細についてthis
は、MDNのドキュメントをご覧ください。
正しい参照方法 this
使わない this
実際にはthis
特にアクセスしたくないが、それが参照するオブジェクト。そのため、簡単な解決策は、そのオブジェクトも参照する新しい変数を作成することです。変数には任意の名前を付けることができますが、一般的なものはself
およびthat
です。
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function() {
alert(self.data);
});
}
self
は通常の変数なので、字句スコープのルールに従い、コールバック内からアクセスできます。これにthis
は、コールバック自体の値にアクセスできるという利点もあります。
this
コールバックの明示的なセット-パート1
のthis
値は自動的に設定されるため、の値を制御できないように見えますが、実際にはそうではありません。
すべての関数にはメソッド.bind
[docs]がありthis
、値にバインドされた新しい関数を返します。この関数の動作は、呼び出したものとまったく同じです.bind
が、ユーザーthis
が設定したものだけです。その関数がいつどのように呼び出されても、this
常に渡された値を参照します。
function MyConstructor(data, transport) {
this.data = data;
var boundFunction = (function() { // parenthesis are not necessary
alert(this.data); // but might improve readability
}).bind(this); // <- here we are calling `.bind()`
transport.on('data', boundFunction);
}
この場合、我々は、コールバックの結合されているthis
の値にMyConstructor
さんthis
。
注: jQueryのコンテキストをバインドする場合は、代わりにjQuery.proxy
[docs]を使用してください。これを行う理由は、イベントコールバックのバインドを解除するときに関数への参照を保存する必要がないようにするためです。jQueryはそれを内部的に処理します。
ECMAScript 6:矢印関数を使用する
ECMAScript 6では、ラムダ関数と考えることができる矢印関数が導入されています。彼らには独自のthis
拘束力はありません。代わりに、this
通常の変数と同じようにスコープで検索されます。つまり、を呼び出す必要はありません.bind
。それだけではありません。詳細については、MDNのドキュメントを参照してください。
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => alert(this.data));
}
this
コールバックのセット-パート2
コールバックを受け入れる一部の関数/メソッドは、コールバックのthis
参照先の値も受け入れます。これは基本的に自分でバインドするのと同じですが、関数/メソッドがそれを行います。Array#map
[docs]はそのような方法です。その署名は次のとおりです。
array.map(callback[, thisArg])
最初の引数はコールバックで、2番目の引数はthis
参照する値です。これは不自然な例です:
var arr = [1, 2, 3];
var obj = {multiplier: 42};
var new_arr = arr.map(function(v) {
return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument
注:this
通常、値を渡すことができるかどうかは、その関数/メソッドのドキュメントに記載されています。たとえば、jQueryの$.ajax
メソッド[docs]には、次のオプションが記述されていますcontext
。
このオブジェクトは、すべてのAjax関連のコールバックのコンテキストになります。
一般的な問題:オブジェクトメソッドをコールバック/イベントハンドラーとして使用する
この問題のもう1つの一般的な症状は、オブジェクトメソッドがコールバック/イベントハンドラーとして使用される場合です。関数はJavaScriptの第一級の市民であり、「メソッド」という用語は、オブジェクトプロパティの値である関数の単なる俗語です。しかし、その関数には、その「包含」オブジェクトへの特定のリンクがありません。
次の例を考えてみます。
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = function() {
console.log(this.data);
};
関数this.method
はクリックイベントハンドラーとして割り当てられますが、がクリックされた場合、document.body
ログに記録される値はになりますundefined
。これは、イベントハンドラー内ではのインスタンスではなくをthis
参照するためdocument.body
ですFoo
。
最初にすでに述べたように、何をthis
参照するかは、関数の定義方法ではなく、関数の呼び出し方法によって異なります。
コードが次のようである場合、関数がオブジェクトへの暗黙的な参照を持たないことがより明白になる可能性があります。
function method() {
console.log(this.data);
}
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = method;
解決策は上記と同じです:可能であれば、特定の値.bind
に明示的にバインドするthis
ために使用します
document.body.onclick = this.method.bind(this);
または、匿名関数をコールバック/イベントハンドラーとして使用して、オブジェクトの「メソッド」として関数を明示的に呼び出し、オブジェクト(this
)を別の変数に割り当てます。
var self = this;
document.body.onclick = function() {
self.method();
};
または、矢印関数を使用します。
document.body.onclick = () => this.method();