こんにちは、ライターのマサトです!
JavaScriptで、thisという記述をよく見かけませんか?
見かけるけれど、よく意味がわかっていなかったり、なんとなーくで使っていたりする人もいるのではないでしょうか?
thisはちょっと考え方が難しいと言われているくらい難易度がちょい高なものなのですが、JavaScriptにおいてかなり重要なものです。
今回はそんなthisを、下記の流れで学習していきましょう!
【基礎】thisとは?
【基礎】thisの使い方
【基礎】thisの呼び出しパターン
【発展】formでthisの活用する方法
【発展】thisとthatの使い分け
thisがわかるようになると、スキルアップを実感できるだけでなくJavaScriptの面白さが数倍アップします!
この機会にぜひ挑戦してみてくださいね。
thisとは?
thisとは、JavaScriptに最初から用意されている特別な変数のことです。
何が特別かというと、呼び出した場所や方法によってその中身が変化するという点です。
これによって非常に便利な変数として機能するのですが、困ったことに理解を難しくさせる要因にもなっています。
この説明だけではthisがどんなものなのかちょっとよくわからないですよね…
そんな時は、まずは使ってみるのが一番!
thisを利用するシーンを想定して、実際にいくつかのパターンをご紹介していきます。
thisの使い方
ここからは、実際にthisを使ったプログラミング手法を勉強していきましょう!
簡単なthisの書き方から、その中身を出力してどのような情報が格納されているのか、具体的に見ていきます。
thisの書き方
thisは、プログラム内のどこでもいつでも単体で利用できる特別な存在です。
そのため、thisには通常のメソッドのような構文も無ければオプション設定などもありません。
例えば、以下のように単体で利用されることもあります。
console.log( this );
この例では、thisをそのまま実行してコンソールログに出力しています。
thisに格納されている値は、thisをどこから実行したのか、またはどのような方法で実行したのかで変化します。
thisの中身を出力する
それでは、thisに格納されている情報がどんなものなのか、その中身を確認してみましょう!
最も簡単な確認方法はコンソールログに出力する方法でしょう。
console.log( this );
実行結果
Window {stop: function, open: function, alert: function…}
実行結果に注目してください!
ごく普通のWindowオブジェクト(グローバルオブジェクト)が出力されていますよね?
つまり、デフォルト状態でthisはwindowオブジェクトとまったく同じという意味になります。
その証拠にthisへ新しいデータを追加すると、どうなるか確認してみましょう!
this.sample = 'こんにちは'; console.log( window.sample );
実行結果
こんにちは
「this.sample」へ文字列を追加しているのに、「window.sample」を表示すると「こんにちは」としっかり出力されています。
つまり、この状態のthisへ文字列を追加するということはwindowオブジェクトに追加するのと同じことなのです。
thisを呼び出すパターン
ここからは、thisを呼び出す場所によってどのように中身が変化するのかを確認していきます。
よく利用される場所としては、関数・メソッド・コンストラクタがあるので、それぞれ詳しく見ていきましょう。
関数で呼び出す
まずは、関数内で利用されるthisの挙動から確認していきます。
例えば、「sample()」という簡単な関数を以下のように作成&実行してみましょう!
function sample() { console.log( this ); } sample();
実行結果
Window {stop: function, open: function, alert: function…}
冒頭でご紹介した例と同じく、Windowオブジェクトが出力されていますね。
つまり、関数の外でも中でもthisに格納されている情報はまったく同じということになります。
メソッドで呼び出す
今度はthisを書く場所を変えてみましょう。
まず、新しくオブジェクトを作成してその中にthisを記述してみます。
var myObj = { name: this, } console.log( myObj.name );
実行結果
Window {stop: function, open: function, alert: function…}
この例では、「myObj」という新しいオブジェクトを作成し、その中のプロパティ「name」へthisの中身を代入しています。
実行結果を見ると、thisの中身が先ほどと同じようにwindowオブジェクトになっていることがわかりますね。
それでは、次にメソッドを作成してその中にthisを記述してみましょう!
var myObj = { name: '太郎', myFunc: function() { //メソッドの中にthisを記述 console.log( this ); } } myObj.myFunc();
実行結果
Object {name: "太郎", myFunc: function}
この例では、オブジェクト内に「myFunc」というメソッドを作成して、その中にthisを記述して出力しています。
実行結果を見ると、今度はwindowオブジェクトではなく自分で作成した「myObj」を参照しているのがわかりますね。
つまり、メソッドの中と外ではthisの中身が変化しているのです。
コンストラクタで呼び出す
もう1つ、thisがよく出てくるケースとしてコンストラクタがあります。
コンストラクタはnew演算子を使ってインスタンスを生成できるわけですが、このインスタンスのプロパティをthisで作成することができます。
function Human( name, age ) { this.name = name; this.age = age; } var taro = new Human( '太郎', 30 ); console.log( taro );
実行結果
Human {name: "太郎", age: 30}
この例では、コンストラクタ「Human」を作成してその中にthisを使ってインスタンスのプロパティを設定しています。
そして、新しくインスタンス「taro」を作成していますが、実行結果を見ると最初にプロパティを作成していたHumanを参照しているのがわかりますね。
つまり、コンストラクタ内のthisは自身のHumanを指しているし、インスタンスのプロパティでもあるというちょっと複雑な意味合いになっている点に注意しましょう。
コンストラクタ、インスタンス、newというキーワードがまだよくわかっていない…
という方は、次の記事でゼロから詳しく解説しているので、ぜひ併せて読んでみてください。
apply / callで呼び出す
少し特殊なthisの呼び出しパターンとして、applyメソッドやcallメソッドを使う方法があります。
applyやcallは、thisの中身を任意のオブジェクトに変更できるメソッドです。
例えば、通常の関数内でthisを呼んでみます。
function show() { console.log( this ); } show();
これを実行するとthisの中身はWindowオブジェクトになりますよね?
この時に、windowオブジェクトではなく任意のオブジェクトに変更できるのがapplyやcallです。
一般的な記述方法としては、下記のように引数へ変更したいオブジェクトを指定します。
関数.apply( 任意のオブジェクト )
次の例を見てください!
var sample = { name: 'taro', age: 32 } function show() { console.log( this ); } show.apply( sample ); show.call( sample );
実行結果
{name: "taro", age: 32} {name: "taro", age: 32}
この例では、新しくsampleというオブジェクトを追加しています。
実行結果を見ると、先ほどはWindowオブジェクトだったのに今回は新しく追加したsampleオブジェクトになっていますね。
ちなみにapplyもcallも、どちらも同じ結果なのですが、関数に引数を設定している場合に違いが出てきます。
function show(num1, num2) { console.log( num1 + num2 ); } show.call( sample, 5, 10 ); show.apply( sample, [5, 10] );
この例では、先ほどの関数「show()」に2つの引数を設定しています。
この時に、callは第2引数以降に「,(カンマ)」で値を設定し、applyは第2引数に配列で値を設定するわけです。
applyやcallについてもっと詳しく知りたい方は、下記の記事もぜひ読んでみてください。
Formでthisを活用しよう
ここからは実用編!
Formを利用した例を詳しく見ていきましょう。
Form内でthisの使い方を学習すると、JavaScriptから効率よくFormの要素を取得できるようになり、非常に便利です。
さまざまな使い道がありますが、なかでも特に便利なコード例をいくつかピックアップしてご紹介します!
thisでIDを取得する
FormのHTML要素内でthisを使うと、その要素自身を参照してくれるのでJavaScriptから操作しやすくなるというメリットがあります。
具体的に言うと、例えばinput要素で作ったボタンの属性として、onclickにthisを指定することでクリックした時にinput要素そのものを取得することができるのです。
次のコード例を見てください!
<body> <form> <!— onclick属性にthisを使ってinput要素そのものを参照する --> <input id="btn1" type="button" value="ボタン1" onclick="getFunc( this.id )" /> <input id="btn2" type="button" value="ボタン2" onclick="getFunc( this.id )" /> </form> <script> function getFunc( id ) { console.log( id ); } </script> </body>
実行結果
btn1
この例ではinput要素で汎用ボタンを作成し、onclick属性に「getFunc( this.id )」というJavaScriptの関数を指定しています。
この時に利用しているthisの中身はinput要素そのものであり、「this.id」と指定することでその要素のIDを取得することが出来るわけです。
そして「ボタン1」をクリックすると、実行結果のようにID名の「btn1」が出力されます。
もちろん、「this.value」とか「this.name」のように、他の属性を指定すればその要素を取得することが可能なので、Formの部品によって処理を変えるような複雑なプログラムを簡単に実現することができるわけです。
thisでForm要素を取得する
先ほどのID取得の例をさらに応用させると、Formの中でForm自身をすべて取得することができます。
これにより、HTML内だけである程度のJavaScriptプログラミングを実行できてしまうので、場合によっては非常に効率よくWebページを作成できるようになります。
例えば、次のコード例はクリックすると「入力フォーム」に記述した文字列が、そのままボタンの名前に変わるというサンプルです。
<body> <form> <input type="text" name="text" /> <input type="button" name="btn" value="ボタン" onclick="this.form.btn.value = this.form.text.value" /> </form> </body>
このコードを実行すると、次のようなフォーム画面が表示されます。
入力フォームに文字列を入れてボタンをクリックすると、「ボタン名」が入力フォームの文字列と同じに変わるのがわかります。
このコード例のポイントは、ボタンのonclick属性の記述です。
簡単に意味を解説しておきます。
「this.form.btn.value」は、このFormの中にあるボタン要素のvalue属性を表している
「this.form.text.value」は、このFormの中にある入力フォームの文字列を表している
このように、「this.form」に続けてForm要素の「name」属性名を記述することで、その要素を取得できるわけです。
使い方さえわかれば簡単で、しかも手軽に扱えるのでFormを作るときにはぜひ試してみてください!
thisでsubmitボタンを作る
先ほど利用した「this.form」の応用例として、普通のbutton要素でsubmitと同じ送信ボタンを作成することも可能です。
<form> <input type="text" /> <button onclick="this.form.submit()" />送信</button> </form>
この例では、Formの中に普通のbutton要素を配置しています。
そのbutton要素の属性としてonclickに「this.form.submit()」と記述しています。
この記述だけでsubmitと同じ効果を持ったことになるわけです。
input要素のtype属性をsubmitにするか、onclick属性に上記の記述をするかの違いで同じ効果を得られるので、どちらの方法でも使えると便利ですね。
thisと似ている?thatとの使い分け
さまざまなプログラムのソースコードを見ていると、this以外にもthatやselfなどの変数を見かけることがあります。
これはthisの中身を見失わないための重要な考え方です。
具体的な意味を詳しく見ていきましょう!
thatは定義されているものではない
まず注意したいのが、thatやselfはthisと違い、もともと定義されているものではありません。
この後説明するケースで、慣習的に使われている変数名である、というだけです。
ちゃんと宣言しないと使えないので、thisとごっちゃにならないように気をつけましょう。
変数thatが必要になるケースとは?
これまで、thisの中身がさまざまな呼び出しパターンによって変化することを学んできました。
このような特徴があることで、プログラムの途中でthisの中身がいつの間にか変化しているケースがよくあります。
例えば、次の例を見てください。
var myObj = { myname: "太郎", getName: function() { console.log("--①の場合--"); console.log( this ); function showName() { console.log("--②の場合--"); console.log( this ); } showName(); } }; myObj.getName();
--①の場合-- Object {myname: "太郎", getName: function} --②の場合-- Window {stop: function, open: function, alert: function…}
この例では、オブジェクトを作成してその中に「getName()」メソッドを定義しています。
この「getName()」の中で、2種類のthisをコンソールログに出力しているのが実行結果からもわかりますね。
注目すべきは、2種類のthisの中身が異なっている点です!
①のthisはメソッド呼び出しなので自身のオブジェクトを出力しています。
しかし、②のthisはメソッド内にありますが通常の関数呼び出しなのでwindowオブジェクトになるのです。
このような違いを見逃してしまうと、想定していたthisの中身では無くなってしまうので不具合の原因になるわけです。
thatを使ってthisを見失わないようにする方法
さて、いつの間にかthisの中身が変わってしまうのを防ぐためにはどうすればよいでしょうか?
最も簡単な方法は、あらかじめthisの中身を変数に代入しておくことです。
なぜなら、thisの中身は呼び出しパターンなどで自動的に変化しますが、変数の中身は自動的に変化しないからです。
一般的にこのようなケースで代入する変数名は、慣例的にthatもしくはselfと命名することが多いです。
これがthatやselfをよく見かける理由というわけですね。
具体的な例を見ていきましょう。
var myObj = { myname: "太郎", getName: function() { //thisの中身を一時的にthatへ代入しておく var that = this; console.log( that ); function showName() { console.log( that ); } } };
この例では、オブジェクト内に定義した「getName()」メソッドの最初にthisの中身を変数thatに代入しています。
これにより、メソッド内のthis(that)と関数内のthis(that)はどちらも自身のオブジェクトを指すことになるわけです。
この方法は自動的に中身が変化するthisを意図的に制御したい場合に有効なので、ぜひ覚えておきましょう!
まとめ
今回は、JavaScriptのthisについて学習をしました!
最後に、もう1度ポイントだけをまとめておきますので、確認しておいてください。
・thisは、呼び出す「場所」や「方法」によって中身が変化する特殊な存在である
・関数、メソッド、コンストラクタ、applyやcallなど、記述する目的によって中身が変化する
・Form要素を取得したり実行する目的でもthisは便利に使える
・thisとselfを使い分けることで、中身の違うthisの混在を防止できる
これらの内容を踏まえて、ぜひ自分のプログラムにも積極的に活用していってくださいね!