更新日:
【JavaScript】 thisについて理解しよう(関数呼び出し編)
thisとは、呼び出し元のオブジェクトのことです。
1
2
3
4
5
6
7
#person = {
tall: 175,
tall_show: function() {
console.log(this.tall);
console.log(person.tall == this.tall)
}
}
上記コードを以下のようにconsoleで確認してみます。
person.tall_show()
を実行すると、personがthisになります。そして、this.tall
としているので、これはthis.tall == person.tall
になることが分かります。
thisの使い方
この章では、thisの使い方について解説します。
関数で呼び出された際のthis
JavaScriptのthisの挙動はややこしく、thisって一体何??と
なっている人も沢山いると思います。
thisとは一言でいうと呼び出し元のオブジェクトになります。
thisにもいろいろ種類があるのですが、今回はthisの中で一番意味を理解しやすい関数で呼び出された際のthisの説明をします。
まず.の前にあるものは全てthisになると考えてください。
person.introduce()←personがthisになる。
teacher.teach() ← teacherがthisになる。
挙動がややこしいものに関しては実際に動画で挙動をみたり自分で打ってみて確かめるのが一番理解できます!
今PCでこの記事を見ている人は下記のサイトからJavaScriptの挙動を確認できるので、thisの動作を自分でも打って確認しましょう。
こちらの動画でいうと、person.tall_show()としたときに、.の手前なので、personがthisになり、this.tallとしているので、これはthis.tall == person.tallになることが分かると思います。
1
2
3
4
5
6
7
person = {
tall: 175,
tall_show: function() {
console.log(this.tall);
console.log(person.tall == this.tall)
}
}
これが一番わかりやすいthisの例です。.の手前になるものがthisということですね。
「.」の前に何もない場合
それでは、.の前に何もない場合はどうなるでしょう。
1
2
3
4
5
window.width = 1280;
function window_width_show() {
console.log(this.width)
}
window_width_show()
なぜ1280と表示されるかというと、thisは.の前に何もない場合は、windowオブジェクトを参照するようになっております。
なので、window.width = 1280としておくと、windowオブジェクトのプロパティにwidthというものが追加されます。
window_width_show()メソッドは.というものがないので、何も参照してませんね。
この場合にはthisはwindowオブジェクトを参照することになっているので、window.widthに設定した値がthis.widthに出力されるというわけです。
関数の中から別の関数を呼び出された場合のthis
ではでは、関数の中からまた別の関数を呼び出された場合のthisはどうなるのでしょう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function test1() {
this.value = 'test1';
console.log(this.value);
}
function test2() {
this.value = 'test2';
console.log(this.value);
}
person = {
test_show: function() {
test2();
}
}
person.test_show();
動画にある通り、test_show()メソッドがtest1()メソッドを呼び出している時はtest1()メソッドで定義されたthis.valueが呼び出されています。
test2()メソッドが呼び出されている時は、test2()メソッドで定義されたthis.valueが呼び出されています。
ただ勘違いして欲しくないのは、test1()メソッドにも.というものがないので、test1()メソッドの中でのthisはtest1()のメソッドのvalueではなくて、windowオブジェクトになります。
test2()メソッドもしかりです。
つまり動画でいうと、test2()メソッドはtest1()メソッドで定義したwindowオブジェクトのvalueプロパティを上書きしているような形になるわけです。
例え関数の中で関数を呼び出すような入れ子になっていても.とオブジェクトのプロパティとして定義していない限り、thisを使えばwindowオブジェクトが参照されるわけです。
ではでは、関数が入れ子の状態で呼び出される時、.が付いていなければ、入れ子でもthisはwindowオブジェクトになっていましたが、.が付いていれば.の前に付いているオブジェクトがthisとして参照されるのでしょうか?
確かめてみましょう。下記の動画を見てください。
動画を見てみると分かると思うのですが、studentという新たなオブジェクトを追加します。
studentを関数で呼び出した場合は、this.valueの値はwindowオブジェクトのvalueというプロパティではなくてstudentオブジェクトのvalueというプロパティに1000と追加されたのが分かると思います。
つまりコンソールに出ているtest2は、windowオブジェクトのvalueプロパティ
コンソールに出ている1000は、studentオブジェクトのvalueプロパティ
.の前に付いている場合は.の前に付いているオブジェクトがthisになる。
.がない場合はwindowオブジェクトがthisになる。
というのが分かって頂けたと思います。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var student = {
value: 1000,
score_show: function () {
console.log(this.value);
}
}
function test1() {
this.value = 'test1';
console.log(this.value);
}
function test2() {
this.value = 'test2';
console.log(this.value);
}
person = {
test_show: function() {
test2();
student.score_show();
}
}
person.test_show();
呼び出されたオブジェクトのthisにする方法
ただ、JavaScriptのthisって関数の中で何も指定してなかったら、thisがwindowオブジェクトになるって面倒臭くないですか?
例えば、以下のような場合だとコンソールにwindowに関して教えます。
と表示されます。
1
2
3
4
5
6
7
8
9
10
11
12
var content = 'windowに関して教えます。'
var teacher = {
content: '数学に関して教えます。',
show_teach_content: function () {
function content () {
console.log(this.content)
}
content();
}
}
teacher.show_teach_content();
上記の例だとteacher.show_teach_content();
と呼び出しており、teacherオブジェクトの中でshow_teach_content()
が実行されます。
その中で直接content
というメソッドを呼び出されるので、このcontentメソッドはwindowオブジェクトに紐づいています。
「windowオブジェクトのcontent→windowに関して教えます。」と表示します。
ただ上記ではなく、「teacherオブジェクトの中で呼び出されているので数学に関して教えます。」と表示されてほしいと思います。
ただcontentメソッドの.の前に何もないのでwindowオブジェクトが参照されてwindowオブジェクトのcontentとして表示されています。
そこで関数から呼び出された時にthisの値をwindowオブジェクトではなく、呼び出されたオブジェクトのthisにする方法が二つあります。
1.変数に格納する方法
下記の様にshow_teach_content();の中でthisを何かの変数に入れれば、その変数はどこにも紐づいていない関数でもteacherオブジェクトのthisとして扱うことができます。
今回はselfという変数に入れましたが、分かり易ければ何でも良いです。
ただ僕が働いている会社ではselfを使っていて、他のところでもselfという記述はよく見かけるので、特にこだわりがなければthisを入れる変数はselfで良いかと思います。
1
2
3
4
5
6
7
8
9
10
11
12
13
var content = 'windowに関して教えます。'
var teacher = {
content: '数学に関して教えます。',
show_teach_content: function () {
var self = this;
function content () {
console.log(self.content)
}
content();
}
}
teacher.show_teach_content();
2.bindメソッドを使用する
bindメソッドとはbindメソッドの前にあるオブジェクトのthisを捕縛することができます。
ん??と言っても良くわからないですよね。。
例えば下記のコードがあるとして
1
2
3
4
function bind_test () {
console.log("bindする値は" + this + "です。")
}
bind_test.bind('programan')()
ここで表示されるのは「bindする値はprogramanです。」
と表示されます。
本来であれば.の前に何もなければthisオブジェクトはWindowオブジェクトを参照することになっているので、「"bindする値は[object Window]です。"」
と表示されるはずですが、
なぜ「bindする値はprogramanです。」と表示されたのか?
その理由はbind_test.bind('programan')とここの部分で、bind_testの中で参照されるthisは'programan'に変更しますよ!
という意味になるからです。
なので、本来はthisオブジェクトが参照するのはWindowオブジェクトのはずですが、bind_test.bind('programan')で
1
2
3
4
function bind_test () {
console.log("bindする値は" + this(←bindメソッドによりプログラマンに変更) + "です。")
}
bind_test.bind('programan')()
となるわけです。
bind_test.bind('programan')()
↑こちらのコードの意味を解説しておくと、bind_test.bind('programan')で、bind_testの中のthisがprogramanに置き換わった、
bind_test.bind('programan')()←ここの()の部分は、thisが'programan'に置き換わったbind_testメソッドを実行しているということになります。
直接呼び出す事もできますが←bind_test.bind('programan')()
実際には変数に入れる事もよくあります。
1
2
3
4
5
6
function bind_test() {
console.log("bindする値は"+ this + "です。")
}
programan_introduce = bind_test.bind('programan')
programan_introduce();
こちらもbind_test.bind('programan')()と同じ表示結果になります。
programan_introduce = bind_test.bind('programan')
↑この部分で、programan_introduceという変数には、bind_testの中のthisオブジェクトがprogramanに変わった状態の関数が入っていることになります。
その関数をprograman_introduce()という形で呼び出すことにより表示ができるということですね。
では、ここでbindの使い方が分かったところで、関数を入れ子にした少しややこしい状態でbindメソッドを実行する動画を下に載せたので実際に自分でも打って動作を確かめましょう。
bindを変数に入れずに直接呼び出す形
bindを変数に入れて呼び出す形
JavaScriptを本格的に学びたい方は、こちらの「初めてのJavaScript 第3版」がおすすめです。基本的な文法から高度な使い方まで非常に広範にわたる内容がこの1冊にまとめられています。
タイトルに「初めての」と付いていますが、完全なプログラミング初心者向けというわけではないので注意が必要です。Rubyなど他の言語を勉強している方にとっては良書となります。
これだけ広範な内容をカバーして丁寧に解説している本はあまりないので、手元に置いておいて損はない1冊です。
この記事のまとめ
.
の前に何もなければthisはwindowオブジェクトが参照される.
があるときは、.
の前に付いているものがthisとして参照される- thisをwindowオブジェクトではなく、呼び出し元のthisに捕縛するには selfという変数に入れるのが良い
- thisをwindowオブジェクトではなく、呼び出し元のthisに捕縛するには bindメソッドを使うのが良い