JavaScript で関数内の this の指す先が、関数オブジェクトを
- (親オブジェクトの)メソッド扱いして実行するか
- コンストラクタ扱いして新しいインスタンスを生成するか
で、変化するという例。
(親オブジェクトの)メソッド扱いして実行する
1.js
var a = {"x" :function(){this.p = 1}};
console.log(a.p); // undefined
console.log(a.x.p); // undefined
//↑ここまでは共通
var x1 = a.x(); // x を a のメソッド扱いして実行、返り値を x1 に格納. 左辺を省いて a.x() だけでも下の結果は変化しない.
console.log(a.p); // 1. this は a を指していた.
console.log(x1.p); // TypeError. x1 が undefined なので.
console.log(a.x.p); // undefined. this は a.x を指しているわけではない.
以上から this は a を指していたことになる。
コンストラクタ扱いして新しいインスタンスを生成する
2.js
var a = {"x" :function(){this.p = 1}};
console.log(a.p); // undefined
console.log(a.x.p); // undefined
//↑ここまでは共通
var x1 = new a.x(); // x をコンストラクタ扱いして新しいインスタンス x1 を生成. new が付いただけで左辺 x1 の意味合いが変わっていることに注意.
console.log(a.p); // undefined. this は a を指していない.
console.log(x1.p); // 1. this は x から生成されたインスタンス x1 を指していた.
console.log(a.x.p); // undefined. this は a.x を指しているわけではない.
以上から this は x から生成されるインスタンスを指していたことになる。
ちなみに、function 内にreturn文を書いた場合の挙動については JavaScript: Constructor Return Value を参照。値を返すだけのreturn文は無視されるが、return {"p":2} としてオブジェクトを返すと、2.js の 10行目は 2 が返ってくる。関数をコンストラクタとして宣言する場合は、関数を大文字ではじめ、return文を書かないことで、メソッドと明確に区別できるようにした方がいいだろう。
参考
- Javascriptでオブジェクト指向するときに覚えておくべきこと - Qiita [キータ]
- JavaScript の this について - IT戦記 (6)とかは実行時の文脈で this が解釈される好例。