JavaScript

【JavaScript】thisの使い方をマスターしよう!

JavaScriptを使った開発をしているとthisは必ず目にすると言っても過言ではない程に使用されます。しかし、thisは挙動がかなり特殊な為、理解せず何となくで使っているとこのthisは何を参照しているのだろう?と混乱してしまいます。

そこで本記事では、JavaScriptのthisの使い方について詳しく解説しています。コピーされた時の挙動やコールバック関数時の挙動なども解説しているのでご参考ください。

JavaScriptの学習におすすめ参考書
改訂新版JavaScript本格入門 ~モダンスタイルによる基礎から現場での応用まで

参考書が苦手な人はUdemyの動画がおすすめ
ガチで学びたい人のためのWEB開発徹底実践(フロントエンド編)

動画情報
作成者CodeMafia
学習時間19.5時間
受講者数28,547人
レビュー (5,025件)
動画の詳細はこちら

thisとは何か?

MDNに掲載されているthisについての説明は以下のとおりです。

関数の this キーワード は、JavaScript ではほかの言語と少々異なる動作をします。また、strict モードであるかどうかでも違いがあります。

ほとんどの場合、this の値はどのように関数が呼ばれたかによって決定されます (実行時結合)。これは実行時に代入によって設定することはできず、関数が呼び出されるたびに異なる可能性があります。ES5 では bind() メソッドが導入され、関数がどのように呼ばれたかに関係なく `this` の値を設定するすることができるようになり、ES2015 では、自身では this の結び付けを行わないアロー関数が導入されました (これは包含する構文上のコンテキストの this の値を保持します)。

引用元:MDN

MDNの解説で一番重要なポイントは「thisの値はどのように関数が呼ばれたかによって決定されます」です。

分かりやすいようにサンプルコードで確認していきましょう。

const infoObj = {
  name: "John",
  sayName: function () {
    console.log(`私の名前は${infoObj.name}です`);
  },
};

infoObj.sayName();

オブジェクト内にあるnameプロパティをsayNameプロパティに定義されている関数で使用したい場合、infoObj.nameで参照することができますが、このinfoObjはthisに置き換えることができます。

console.log(`私の名前は${infoObj.name}です`); // -> 私の名前はJohnです
console.log(`私の名前は${this.name}です`); // -> 私の名前はJohnです

何故このような結果になるのか?その答えinfoObj内でthisを使用した場合、thisは呼び出し元のオブジェクト(infoObj)への参照を保持するキーワードになるからです。

それじゃあ、「infoObj.sayName();」のinfoObjもthisで代用できるの?と思いますよね。しかしこのinfoObjはthisで代用することができません。

その理由は、infoObj内ではないからです。もし呼び出し元オブジェクトが存在しない状況でthisを使用した場合、そのthisはグローバルオブジェクトを参照します。

infoObj.sayName(); // -> infoObjを参照する
this.sayName(); // -> グローバルオブジェクトを参照する

コピーされた時のthisの挙動

続いて、オブジェクト内の関数をコピーした時のthisの挙動を確認してみましょう。先ほどのサンプルコードを使います。

const infoObj = {
  name: "John",
  sayName: function () {
    console.log(`私の名前は${this.name}です`);
  },
};

infoObj.sayName(); // -> 私の名前はJohnです

const copyObj = infoObj.sayName;
copyObj(); // -> 私の名前はです

実行してみると、コピーした関数を実行した時にオブジェクト内のnameプロパティが参照できておらず、「私の名前はです」とおかしな出力がされていることが確認できます。

この原因は、thisの呼び出し元のオブジェクトがinfoObjからcopyObjに変更されたからです。nameプロパティはinfoObj内にあるため、この値を参照するにはinfoObjが呼び出し元のオブジェクトである必要があります。しかし、コピーをするとcopyObjが呼び出し元のオブジェクトになるため、thisはグローバルオブジェクトを参照します。

本当にグローバルオブジェクトを参照しているか確認してみましょう。グローバルオブジェクトにプロパティを追加するには、window.プロパティ名 = 値の形で記述します。

window.name = "Michael"; // -> グローバルオブジェクトにnameプロパティを追加

const infoObj = {
  name: "John",
  sayName: function () {
    console.log(`私の名前は${this.name}です`);
  },
};

infoObj.sayName(); // -> 私の名前はJohnです
const copyObj = infoObj.sayName;
copyObj(); // -> 私の名前はMichaelです

実行してみると、コンソールにグローバルオブジェクトのnameプロパティに追加したMichaelが出力されていることが確認できます。

コールバック関数でthisを使った時の挙動

最後にコールバック関数でthisを使った時の挙動を確認してみましょう。先ほどのサンプルコードに少し改良を加えた以下のコードを使います。

window.name = "Michael";

const infoObj = {
  name: "John",
  sayName: function () {
    console.log(`私の名前は${this.name}です`); // -> 私の名前はMichaelです
  },
};

function infoFn(callback) {
  callback(); // -> 渡されたinfoObj.sayName関数を実行
}

infoFn(infoObj.sayName); // -> infoObj.sayNameを実引数に設定

上記のコードを実行すると「私の名前はMichaelです」とコンソールに出力されます。これはコピーした時と同様にthisがグローバルオブジェクトを参照しています。

この理由もコピーした時と同様に、thisの呼び出し元のオブジェクトがinfoObjではなくなっていることが原因です。

【JavaScript】コールバック関数とは?仕組みから使い方まで徹底解説本記事では、JavaScriptのコールバック関数の仕組みから使い方まで誰でも理解できるように徹底解説しています。...

ブログランキング・にほんブログ村へ PVアクセスランキング にほんブログ村