Yuri's Blog
勉強する猫さん

JavaScriptのthisの挙動について呼び出し元で整理する

公開日:2024年11月20日

最終更新日:2024年11月20日

JavaScript

こんにちは、Yu_riです。
今回はPJや個人開発で振り回されることが多かった、JavaScriptの「this」の挙動について今一度振り返ってみることにしました。
自分をはじめ初学者の方は知っておくと開発が楽になるかと思います。

そもそも「this」ってなんだ?


thisは一言で言うと「オブジェクトへの参照を保持するキーワード」です。
使用する場所によってどのオブジェクトを参照するのかが決まると言うのが、特徴でもありいいところでもあり、難しいところでもあります。。
それでは、使用する場所で参照するオブジェクトがどう違うのか見てみます。

使用する場所ごとのthis


thisを使用する場所(ケース)は以下の2種類です。

  • オブジェクトのメソッドで使用される場合
  • 関数で使用される場合

オブジェクトのメソッドで使用される場合


この場合のthisは「呼び出し元のオブジェクト」への参照を保持しています。
ここでいう「呼び出し元のオブジェクト」とは、以下の例でいうobjの事です。

const obj = {};

実際に挙動を見てみましょう。

const obj = {
  name: "Yu_ri",
  message: function () {
    console.log("Hello " + this.name);
  }
};
obj.message();

上記の例では、「Hello Yu_ri」と出力されます。
つまり this.name は obj.name と解釈されているということです。
このようにオブジェクトのメソッドでthisが使用される場合は、「呼び出し元のオブジェクト」の参照を保持していることがわかります。

関数で使用される場合


この場合のthisは「グローバルオブジェクト = windwオブジェクト」への参照を保持しています。
こちらも実際に挙動を見てみましょう。

window.name = "Yu_ri";
function message () {
  console.log("Hello " + this.name);
}
message();

上記の例でも、「Hello Yu_ri」と出力されます。
つまり this.name は window.name と解釈されているということになります。

ちなみに「window.name」の部分を「let name」や「const name」として定義しても結果は「Hello undefined」となります。理由は、letやconstで定義された変数はwindowオブジェクトのプロパティとして追加されないからです。
(varはwindowオブジェクトのプロパティとして追加されます。)

おまけ


ここまで理解した上でオブジェクトのメソッドを変数にコピーした場合はどういう挙動になるのか見てみましょう。

const obj = {
  name: "Yu_ri",
  message: function () {
    console.log("Hello " + this.name);
  }
};
const message = obj.message;
message();

上記の例では、「Hello undefined」と出力されます。
この理由についてみていきましょう。

オブジェクトのメソッドを関数化した際の挙動
先ほどのオブジェクトのメソッドを変数にコピーした部分を見てみましょう。

const message = obj.message;

ここで何が起きているのかというと「obj.messageが持っているオブジェクトへの参照」を変数messageにコピーしているのです。
※オブジェクト?と思った方は以下のこちらの記事を参考にしてみてください。

そのため変数messageは↓のイメージになります。

const message = function () {
    console.log("Hello " + this.name);
};

変数messageは、関数式となるので当然関数として実行できます。

先ほど関数でthisが使用される場合で記載した通り、関数でのthisはグローバルオブジェクトを参照します。
上記の例ではグローバルオブジェクトにプロパティを追加していませんので、「Hello undefined」が出力されたということになります。

ここでは詳しく記載しませんが、こういった場合に「bind」というメソッドを使用します。

const message = obj.message.bind(obj);
message(); //出力結果は「Hello Yu_ri」

まとめ


【 thisの挙動 】

  • オブジェクトのメソッドで使用される場合

→「呼び出し元オブジェクトへの参照」を保持

  • 関数で使用される場合

→「グローバルオブジェクト = windwオブジェクト」を保持