JavaScriptのthisと名付けられた特殊なキーワードは他のプログラム言語と違うコンセプトを持っています。JavaScriptのthisは正確に5個の別々の使い道が存在しています。
this;
thisをグローバルスコープ内で使用すると、単純にグローバルオブジェクトを参照するようになります。
foo();
このthisは、再度グローバルオブジェクトを参照しています。
ES5での注意: strictモードでは、このグローバルのケースはもはや存在していません。 この場合
thisはundefined値を代わりに持つことになります。
test.foo();
この例ではthisはtestを参照します。
new foo();
newキーワードが付いた関数呼び出しはコンストラクターとして機能します。関数内部ではthisは新規に作成されたObjectを参照します。
function foo(a, b, c) {}
var bar = {};
foo.apply(bar, [1, 2, 3]); // 配列は下記で展開される
foo.call(bar, 1, 2, 3); // 結果はa = 1, b = 2, c = 3
Function.prototypeのcallやapplyメソッドを使用した時には、呼び出された関数の内部でのthisの値は、対応する関数呼び出しの最初の引数に明示的に設定されます。
結果として、上記の例ではメソッドケースが適用されず、fooの内部のthisはbarに設定されます。
注意:
thisはObjectリテラル内部のオブジェクトを参照しません。 ですので、var obj = {me: this}でのmeはobjを参照しません。thisはここで紹介ている5個のケースの内どれか一つに束縛されます。
これらのケースのほとんどは理にかなったものですが、最初のケースは実際に利用されることが絶対にないので、間違った言語設計だとみなせるでしょう。
Foo.method = function() {
function test() {
// このファンクションはグローバルオブジェクトに設定される
}
test();
}
良くある誤解としてtestの中のthisがFooを参照しているというものがありますが、そのような事実は一切ありません。
testの中のFooにアクセスする為には、Fooを参照するmethodのローカル変数を作る必要があります。
Foo.method = function() {
var that = this;
function test() {
// ここでthisの代わりに使用する
}
test();
}
thatは通常の変数名ですが、外部のthisの参照の為に良く使われます。クロージャと組み合わせる事でthisの値を渡す事ができるようになります。
JavaScriptを使用する上で、もう一つ動かないものが関数のエイリアスです。これは変数へメソッドを割り当てする事です。
var test = someObject.methodTest;
test();
最初のケースのtestは通常の関数呼び出しになる為に、この中のthisは、もはやsomeobjectを参照できなくなってしまいます。
thisの遅延バインディングは最初見た時にはダメなアイデアに見えますが、プロトタイプ継承により、きちんと動作します。
function Foo() {}
Foo.prototype.method = function() {};
function Bar() {}
Bar.prototype = Foo.prototype;
new Bar().method();
methodがBarのインスタンスにより呼び出された時に、thisはまさにそのインスタンスを参照するようになります。