kanou

JavaScript thisの参照先基本パターン

最近JavaScriptを学習する上で、thisの参照先についてややこしく感じたので、この記事ではthisの参照先について基本的なパターンを整理してみました。

thisとは

thisとはJavaScriptに最初から用意されている特別な変数のことです。
条件(実行場所)によって参照先が異なり、この条件によって参照先が変わることで意図しない値(undefined)になることが多いです。

紹介パターン

今回は「非厳格モード」を前提に、下記のパターンについてまとめました。

1.何にも含まれていない状態
2.関数内
3.メソッド内
4.constructor内
5.グローバルオブジェクトに格納されているメソッド内
6.thisの参照先を指定する方法

1.何にも含まれていない状態

クラスや関数内など何にも含まれていない状態でthisを呼び出すとブラウザのグローバルオブジェクトであるwindowを参照します。

※windowオブジェクト:ブラウザでサイトを表示している状態の変数やメソッドなどを格納しているオブジェクト。

試しに下記のプログラムを実行してみるとwindowオブジェクトを参照していることが分かります。
console.log(this);// Window{parent: Window, opener: null, top: Window, length: 0, frames: Window,…}
// windowオブジェクトを参照
  ※thisの参照先を確認した場合は、確認したい場所でconsole.log(this)を入力し、デベロッパーツールの「Console」で確認することもできます。

2.関数内

単に関数内で呼び出す場合でも、thisはグローバルオブジェクト「window」を参照します。
function sample() {
  console.log(this); // windowオブジェクトを参照
}

sample();// Window{parent: Window, opener: null, top: Window, length: 0, frames: Window,…}

3.メソッド内

メソッド内で呼び出す場合では、thisは呼び出し元のオブジェクト「person」を参照します。
関数内とは異なり、元々用意されているグローバルオブジェクトではなく、直近で囲まれているオブジェクトを参照することになります。

const person = {
  name: "山田",
  callName: function () {
    console.log("私の名前は" + this.name + "です"); // personを参照
  }
};

person.callName();// 私の名前は山田です
※オブジェクトとは「プロパティ」と「値」の組み合わせになるが、この「値」の部分に関数を当てはめたのがメソッド。

4.constructor内

constructor内で呼び出す場合、thisはnew演算子でインスタンス化された変数のオブジェクト「obj」のことを指します。 そのため下記のプログラムを実行するとデベロッパーツールのConsoleでは「obj」に格納されているPersonクラスが表示されます。
class Person {
  constructor(name) {
    this.name = name; 
  console.log(this);// objを参照
  }
}

const obj = new Person("山田");
console.log(obj.name); // 山田

5.グローバルオブジェクトに格納されているメソッド内

上記のようにメソッド内で呼び出す場合でも、setTimeoutメソッドのように"グローバルオブジェクトに格納されているメソッド"内でthisを呼び出す場合においては、windowオブジェクトを参照するので注意が必要です。

const person = {
    name: "山田",
    callName: function () {
      setTimeout(function () {
        console.log("私の名前は" + this.name + "です"); // windowオブジェクトを参照
      }
     );
    }
  };

person.callName();// 私の名前はです
// windowオブジェクトを参照するため"this.name"の部分は表示されない

これはthisが決定するロジックとして、直近で囲まれている(最初に見つかる)オブジェクトを基本的に参照するためです。

上記のコードではsetTimeoutの頭にオブジェクト名は記述されておりませんが、正確には

 
window.setTimeout(function () {
  console.log("私の名前は" + this.name + "です");// windowオブジェクトを参照
});
 

と記述されます。

※グローバルオブジェクトは省略が可能なので一般的には省略して記述します。

6.thisの参照先を指定する方法

thisを指定する方法はいくつかありますが、ここでは2つ紹介します。

1)bind
bindとは、関数に対してthisや引数を指定することができるメソッドです。
thisを書き換えることによって、参照するプロパティを変更できます。

先ほどの「3.グローバルオブジェクトに格納されているメソッド内」で説明したsetTimeout内のthisをwindowオブジェクトからpersonオブジェクトに変更する場合下記のように記述します。

const person = {
  name: "山田",
  callName: function () {
    setTimeout(
      function () {
        console.log("私の名前は" + this.name + "です"); // personオブジェクトを参照
      }.bind(this)
    );
  },
};

person.callName();// 私の名前は山田です
上記のように記述することで呼び出し元のオブジェクト「person」をthisが参照するオブジェクトに確定することができます。
※「bind(person)」のように直接オブジェクト名を指定しても同じ結果となります。

2)アロー関数で事前にthisを確定する
アロー関数を用いることにより、bindと同じようにthisが参照するオブジェクトを確定させることができます。
これまで説明してきた通り、thisは使う場所によって参照先が変化するため、常にどこを参照しているのか?を意識する必要がありました。
しかし、ES6以降にアロー関数が登場し、事前に参照先を確定することができるようになり、そのような心配は少なくなりました。

const person = {
  name: "山田",
  callName: function () {
    // アロー関数式で宣言する
    setTimeout(() =>{
      console.log("私の名前は" + this.name + "です");// personオブジェクトを参照
      // bind(this)は不要
    });
  },
};

person.callName();// 私の名前は山田です

この場合でも1)の時と同じ結果となります。

まとめ

・thisの基本的なロジックとして直近で囲まれている(最初に見つかる)オブジェクトを参照する。
・クラス外、関数内のthisは基本的にグローバルオブジェクトを参照する。
・グローバルオブジェクトに格納されているメソッド内でthisを使用する場合は注意が必要。
・bindやアロー関数により、thisの参照先を指定することができる。

新しいウェブ体験を作ろう TAMのPWA開発
お問い合わせはこちら