#javascriptの「this」は「4種類」??
この記事ではベースとなる4種類の「this」を紹介します。
実際は4種類ではないのですが、
このベースの4種類を理解できれば他もすぐに理解できます。
#thisの4種類のパターン
1:メソッド呼び出しパターン
2:関数呼び出しパターン
3:コンストラクタ呼び出しパターン
4:apply,call呼び出しパターン
ここで重要なのは「呼び出し元」をみることです。
なぜなら「呼び出し元」に「this」は左右されるからです。
#メソッド呼び出しパターン
これはもう一番直感的にわかりやすいです。
説明はいらないんじゃないかという感じなのですが、
一応ソースを。。
//メソッド呼び出しパターン
var myObject = {
value: 10,
show: function() {
console.log(this.value);
}
}
myObject.show(); // 10
かなり直感的ですね。
thisにはmyObjectが入っています。
#関数呼び出しパターン
関数とメソッドと二つの呼び方をしてるのが、
ややこしく聞こえるかもしれません。
ただコードを見たらすぐに理解できます。
myObject.show(); // メソッド呼び出し
show(); // 関数呼び出し
「.」で呼ばれているかどうかの違いのみですね。
では関数呼び出しパターンの「this」はいかに…
function show() {
console.log(this);
this.value = 1; // 注1
}
show(); // thisはグローバルオブジェクトをさす
この場合は「this」は「グローバルオブジェクト」を指してしまいます。
なので、注1の「value」は「グローバル変数」となります。
これを抑えておくのがポイントです。
次の例を考えてみましょう。
var myObject = {
value: 1,
show: function() {
console.log(this.value); // 注1
function show() {
console.log(this.value); // 注2
}
show();
}
};
myObject.show();
ここで注1と注2の答えはわかりましたか?
注1の「this.value」は「1」
注2の「this.value」は「undefind」
注1は一つ目のメソッド呼び出しパターンですね。
注2が最初紛らわしいです。。
メソッド呼び出しの中で関数呼び出しされているので、
あくまで注2の「this」はグローバルを指してしまいます。
メソッド内で関数呼び出しになっているっていうのが落とし穴ですね。
でもこれも簡単に解決できます。
var myObject = {
value: 1,
show: function() {
var self = this;
console.log(self.value); // 1
function show() {
console.log(self.value); // 1
}
show();
}
};
myObject.show();
「this」を別の変数で持っておきます。この手法はよく使われます。
慣用的に変数は「self」, 「that」, 「_this」のどれかが使われる事が多いです。
#コンストラクタ呼び出しパターン
次はコンストラクタ呼び出しパターンです。
function MyObject(value) {
this.value = value;
this.increment = function() {
this.value++;
};
}
var myObject = new MyObject(0);
console.log(myObject.value); // 0
myObject.increment();
console.log(myObject.value); // 1
これもこれだけみるとわりと直感的ですね。
「new」をつけてインスタンス生成ってことですね。
そしてその生成されるインスタンス自身が「this」にsetされます。
ただ気をつけたいのが、これはただの「関数」です。。
「new」をつけなかった場合,
MyObject(0);
これは関数呼び出しなので、
「this」はグローバルオブジェクトを指してしまいます。。
この場合はvalueとincrementは
二つともグローバル変数として定義されることになります。
コンストラクタ呼び出しを期待する場合は、
最初の文字を大きくするのが慣例ですので、この場合は「new」は必ずつけましょう!
#apply, call呼び出しパターン
これは「this」を好き勝手に設定できますよっていうことです。
ライブラリとかを自作するときは非常に重宝します。
var myObject = {
value: 1,
show: function() {
console.log(this.value);
}
};
var yourObject = {
value: 3
};
myObject.show(); // 1
myObject.show.apply(yourObject); // 3
myObject.show.call(yourObject); // 3
「apply」と「call」を使うと「強制的にthisを束縛」できます。
「apply」と「call」の第一引数は「this」にsetしたいオブジェクトです。
あれ?…じゃあ「apply」と「call」は何が違うのかって、
それは第二引数以降の取り方が変わってきます。
var myObject = {
add: function(value1, value2) {
console.log(this.value + value1 + value2);
}
};
var yourObject = {
value: 3
};
myObject.add.apply(yourObject, [2, 10]); // 15
myObject.add.call(yourObject, 2, 10); // 15
「apply」は第二引数に配列をとり、配列の中身が引数として渡されます。
「call」は直感的で、第二引数以降がそのまま渡されます。
二つとも第一引数は「this」で、その後の引数の取り方が違うだけです。
#まとめ
「呼び出し元」に気をつけろ!
覚えるべきベースは4種類。
1:メソッド呼び出しパターン
2:関数呼び出しパターン
3:コンストラクタ呼び出しパターン
4:apply,call呼び出しパターン
てな感じです。
あっさりまとめたので、わからないところがあれば聞いてください♪
それからコンストラクタについて詳しく知りたい方はこちら
JavaScriptのクラス?コンストラクタ?
外部アカウント
技術情報のみつぶやくアカウント作成しました。JavaScriptは最新情報も追っていきます。
[Twitterはこちら]
(https://twitter.com/takeharumikami)
[Feedlyのフォローはこちら]
(http://cloud.feedly.com/#subscription%2Ffeed%2Fhttp%3A%2F%2Fqiita.com%2Ftakeharu%2Ffeed)
おすすめの記事
もういい時期です。そろそろ始めましょう。ECMAScript6。
もうはじめよう、ES6~ECMAScript6の基本構文まとめ(JavaScript)
JavaScriptはオブジェクト指向?プロトタイプベースのオブジェクト指向を学ぶなら。
JavaScriptのプロトタイプからオブジェクト指向を学ぶ
JavaScriptでは関数はすべてクロージャ。
そもそもクロージャって?JavaScriptでクロージャ入門