this とは
JavaScript(以下JS)のコードを読んでいると、this
がたくさん出てくることあると思います。
JSのコードでthis
が出てくると、「このthis
って何を指しているのだろうか?」と勉強したての頃はよくなりました。
this
は日本語訳すると「これ」です。代名詞です。
JSになると「この」プロパティを指すか、「この」関数を指すか、このオブジェクトを指すか、this
の前後によって意味が異なります。JSの始めたての人はこのthis
でつまずきやすいのでないでしょうか。しかし逆を言うとこのthis
を把握することによってコードの理解力が上がると思います。
this
の注意点
上記でも述べましたが、「これ」といってるだけで呼び出した場所や方法によってその中身が変化します。要点を抑えて正しいthis
の把握をしていきましょう。
最初に大事なことを言うと、thisの意味を把握するうえでの基準は.
(ドット)です。
※最後の方ではドラえもんの例でごり押ししているので、ご了承ください。
this
の使い方
this
の中身はいろいろ変化しますが、だいたいパターンは決まっています。次の5種類くらいです。
- グローバルオブジェクト
- メソッドチェーン
- 関数呼び出し
- コンストラクタ呼び出し
-
call
とapply
以下、それぞれの種類を説明していきます。
1.グローバルオブジェクト
説明
関数の呼び出しにおいて.
がない場合は、グローバル変数的なthisを呼びます。つまりwindow
プロパティです。
具体例
function test() {
console.log(this);
}
test(); //.がない
//結果
//Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
2. メソッドチェーン
説明
関数の呼び出しにおいて.
がある場合は、その前のオブジェクトを指します。これは一般的な代名詞使用法です。以下の具体例でいうと【「この」オブジェクトのshow
関数を実行します!!】と叫んでいるのが「myObject.show();
」です。ここではオブジェクトのthis.name
、すなわちmyObject
のname
であるmk0812
を呼びます。ここまでのthis
記法は多分まだ簡単だと思います。
具体例
var myObject = {
name: 'mk0812',
show: function(){
console.log(this.name);
}
}
myObject.show(); //.がある場合はその前のオブジェクトを指す
//結果
//mk0812
3.関数呼び出し
説明
ここから本番です。関数呼び出しとはメソッドの中で関数を呼ぶことです。言ってることがさっぱりわからないので具体例の中で説明しましょう。
具体例
var myObject = {
name: 'mk0812',
show: function(){
console.log(this.name); //①
function show(){
console.log(this.name); //②
}
show();
}
}
myObject.show(); //.がある場合はその前のオブジェクトを指す。がメソッドの中にthisを参照する関数がある。
//結果
//①.. mk0812
//②.. undefined
この場合は、①は2.メソッドチェーン
同様にmk0812
を指しますが、②のthis
はundefined
を指します。ここで②のthisはグローバルオブジェクトを呼び出しています。気を付けてほしいのはメソッド内で関数呼び出しになっている場合はthisの中身は引き継がれないことです。そのメソッド内ではshow();
と定義されています。このshow();
は誰からも定義されていないので、.
がない関数呼び出しとしてグローバルオブジェクトを呼び出します。
undefined
はやだ!かわいそう!というのなら、そのthis
を別の変数(self
)で置き換えて呼びましょう。
var myObject = {
name: 'mk0812',
show: function(){
var self = this;
console.log(this.name); //①
function show(){
console.log(self.name); //②
}
show();
}
}
myObject.show();
//結果
//①.. mk0812
//②.. mk0812
4.コンストラクタ呼び出し
説明
コンストラクタ呼び出しは、new
をつけてインスタンスを生成します。
そのインスタンスの中身のthis
はインスタンス自身になります。
これはnew
をつけるかつけていないかでは、全然違います。
new
をつけていない場合はただの関数です。つまりMyObject('mk0812')
;の場合は関数呼び出しです。グローバル変数のthis
にname
が定義されます。インスタンスとして呼びたい場合は必ずnew
をつけましょう!
具体例
function MyObject(name){
this.name = name;
this.add = function(value){
this.name = this.name + value;
}
this.show = function(){
console.log(this.name);
}
}
var mk = new MyObject('mk0812');
mk.add('aaa');
mk.show();
//結果
//mk0812aaa
5.call
と apply
説明
call
と apply
は「this」を自由に操りたい場合、この方法を用いられます。最初は僕はさっぱりわかりませんでした。僕の勝手なイメージですが、この記法は自作のライブラリとかを作りたい場合、よく使われる印象があります。この「apply」と「call」を使うと「強制的にthisを束縛」できます。僕は「は?束縛?意味わからん」となりました。ここは分かりやすく「ドラえもん」で具体例を出しましょう。
具体例
のび太とジャイアンの関係性でいうと、のび太はジャイアンより弱い設定です(秘密道具を使うとかはなしにしましょう)。のび太が手に入れた漫画はすべてジャイアンのものになります。悲しい世界だ。。。
var nobita = {
book: 'これはのび太の漫画だよ',
show: function() {
console.log(this.book);
}
};
var jian = {
book: 'お前のものはおれのもの、おれのものはおれのもの'
}
nobita.show.apply(jian) //'お前のものはおれのもの、おれのものはおれのもの'
nobita.show.call(jian) //'お前のものはおれのもの、おれのものはおれのもの'
「apply」と「call」の第一引数は「this」にsetしたいオブジェクトです。のび太はジャイアンのjian
オブジェクトに完全に支配され、bookプロパティが上書きされました。これだけ見ると「apply」と「call」の違いはあまりなさそうですが「apply」と「call」の違いは第二引数以降の取り方です。
var nobita = {
book: 'のび太の漫画だよ',
show: function(book1,book2) {
console.log(book1,book2 + 'は' + this.book);
}
};
var jian = {
book: 'おれのもの'
}
nobita.show.apply(jian,['どら焼きの本','カレーの本']); //どら焼きの本 カレーの本はおれのもの
nobita.show.call(jian,'どら焼きの本','カレーの本'); //どら焼きの本 カレーの本はおれのもの
「apply」は第二引数に配列をとり、配列の中身が引数として渡されます。
「call」はそのまま第二引数以降が引数として渡されます。
その他
bind
bindは強制的にオブジェクトと結びつける関数です。
function nobita(){
console.log(this);
}
var jian = {
book: 'おれのもの'
}
var another_jian = nobita.bind(jian);
another_jian();
//結果
//'おれのもの'
関数 another_jian
の呼び出しには .
がついていませんが、 bind
されているので、呼び出し時に jian.
が付く形になります。そのためanother_jian
のthis
はjian
(別のジャイアンもジャイアンとなる)
まとめ
結局、this
ってなんだっけ?ドラえもんだっけ?となった方にまとめを書きます。基本的には.
を見て判断しましょう。使い方は次の5種類です。
- グローバルオブジェクト ..
.
がない→グローバルオブジェクト - メソッドチェーン ..
.
がある→.
の前のオブジェクトを指す。 - 関数呼び出し .. メソッドの中の関数の
this
はグローバル - コンストラクタ呼び出し ..
new
をつけようね -
call
とapply
..this
束縛マン
いろいろ、後で追記するかもしれませんが僕なりにまとめてみました。
以上、最後まで読んでいただきありがとうございました。