JavaScriptでthisが使えるようになる!thisの参照先を説明

JavaScriptでthisが使えるようになる!thisの参照先を説明
公開
thisはプログラムを記述する上で便利な変数で、JavaScriptを学習する上で覚えておきたいものの一つです。thisは使用される場所によって参照する対象が変わるという性質を持っており、関数やメソッド、コンストラクタなどでそれぞれ内容が変わってきますので、混乱することのないようしっかりと理解しておきましょう。

JavaScriptのプログラム上では、「this」と言う変数が使われていることが珍しくありません。使いこなすことができればとても便利なものですが、性質を理解しないまま使用すると混乱してしまうことも考えられます。
今回は、thisにどんな意味があるのかの解説と、基本的な使い方にはどのようなものがあるのかを紹介していきます。

JavaScriptに出てくるthisとは?

thisはスクリプト内のどこからでも利用できる特別な変数です。どこでも参照することができるという変わった性質を持っており、メソッドのような構文、オプション設定も存在しません。

しかし、そのためにthisそのものの実態は分かりにくく、間違ったプログラムを記述してしまうこともあります。結果的にバグを生む原因にもなりやすいため、thisの使い方には十分注意する必要があります。

中身の変化する変数

thisの性質を簡単に説明すると「中身が変化する変数」であると言え、どのような文脈で使用するのかが重要になってきます。まずは、thisをどこで使用すると何を参照するのかを理解できるようになりましょう。

呼び出し方に対応したthisの参照先

使用場面によって中身が異なるthisの具体例を見ていきましょう。
ここでは、使用場面が多い関数やメソッド、コンストラクタ、callメソッドおよびapplyメソッドにおけるthisの使い方を紹介していきます。

関数での呼び出し

ある関数の中でthisを使用した場合、thisはグローバルオブジェクトを参照します。グローバルオブジェクトとは、グローバル変数やグローバル関数を管理するためのJavaScriptにおける便宜的なオブジェクトであり、インスタンス化などはできません。

function sample() {
  console.log(this);
}
sample();

などと記述すればグローバルオブジェクト、例えばWindowオブジェクトなどが表示されます。Windowオブジェクトとは、JavaScriptのオブジェクト階層最上位に位置するオブジェクトで、すべてのオブジェクトの親となります。単に関数内でthisを使った場合にはこのようにグローバルオブジェクトを参照します。

ちなみに関数の外、トップレベルにおいてthisを使用した場合も同じようにグローバルオブジェクトを参照します。

メソッドでの呼び出し

メソッドで読み出す場合、呼び出し元のオブジェクトを参照することになります。以下のようなプログラム例を実行してみましょう。関数で呼び出したときとは異なる結果が得られます。

var sample = {
    myFunction: function() {
        console.log( this );
    }
}
sample.myFunction();

今度は元から用意されているグローバルオブジェクトではなく、生成したオブジェクトsampleを参照していることが分かるかと思います。
ただし、メソッドではなく、プロパティの場合には生成したオブジェクトを参照しません。プロパティの値をthisで代入したとしても、そのプロパティを保有するオブジェクト名が参照されることはなく、グローバルオブジェクトが参照されるだけです。

コンストラクタでの呼び出し

コンストラクタで呼び出す場合、thisは生成したインスタンスを参照することになります。以下のプログラム例を見てみましょう。

var Sample = function(price) {
    this.price = price;
}
var money = new Sample(100);
console.log(money);

このプログラムを実行すると、生成したインスタンス「Sample」を参照します。

call/applyメソッドでの呼び出し

次に、callメソッドおよびapplyメソッドで呼び出した場合にthisが参照するものを説明しますが、これは引数で指定されたオブジェクト、ということになります。
例えば、最初に紹介した関数内でのthisの呼び出しではグローバルオブジェクトが参照されていましたが、callメソッドやapplyメソッドを使うことでグローバルオブジェクト以外の任意のオブジェクトを参照するように変えることができます。

関数.call(オブジェクト名)

もしくは

関数.apply(オブジェクト名)

というように記述すると参照先のオブジェクトが指定できます。

var myObj = {
 number: 1
}

function sample() {
  console.log(this);
}
 
sample.call(myObj);
sample.apply(myObj);

このプログラムを実行すれば、callメソッドとapplyメソッドによって指定されたオブジェクト「myObj」が参照されます。
このような使い方だとcallメソッドもapplyメソッドも同じ結果になりますが、これらは実行する関数に渡す引数の指定方法が異なります。callメソッドでは値を個々に指定しますが、applyメソッドでは配列でこれを渡します。

アロー関数におけるthisの使い方

ES6からはアロー関数と呼ばれるものが利用できます。アロー関数を使えば関数リテラルは簡単に記述できるようになります。

例えば、functionキーワードは書く必要がなくなり、その代わりにアロー(=>)で引数と関数をつなぐだけでよくなります。さらに関数の本体を記述する場合、通常は波括弧{}でブロックを表しますが、本体が1文であればこれを省略することもできます。ほかにも、return命令が省略できるなど、使い方を知ればプログラムを記述するスピードが上げられるでしょう。

ただし、thisをこのアロー関数において使用する場合には注意が必要です。なぜならアロー関数ではthisを固定するという性質があるからです。

アロー関数を使って出力してみます。

x = 'Global';
let myFunc = () => {
  console.log(this.x);
}
let y1 = {
  param: 'y1',
  func: myFunc
}
let y2 = {
  param: 'y2',
  func: myFunc
}
y1.func();
y2.func();

この場合には「y1」「y2」とは表示されず、どちらも「Global」と表示されるようになります。つまり、最初に宣言された時点でthisの内容が決まっているということが分かるかと思います。

まとめ

thisは、使う場面によってその中身が変わる便利な変数です。ただし、thisがどこを参照しているのかを理解して使わないと何を意味するのか分からなくなり、思わぬ挙動を起こすことにもなりかねません。

関数においてthisを使った場合にはグローバルオブジェクト、メソッドでは呼び出し元のオブジェクト、コンストラクタではインスタンス、callメソッドおよびapplyメソッドでは引数で指定したオブジェクトが参照されます。

さらに、ES6から登場したアロー関数を使用する場合にはそこでのthisの働きに注意し、宣言したところで中身が固定されるということを意識して使っていかなければなりません。


この記事のキーワードに関する勉強会・イベントを探す

TECH PLAYでは、ITエンジニア向けの勉強会・イベント情報を提供しています。
興味のある方はぜひご参加ください。


読んだコラムに関連するイベント

類似のコラム

タグからイベントをさがす