【Amazon】人気の商品が日替わりで登場!
毎日お得なタイムセール!商品をみる

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

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

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

JavaScriptの学習におすすめ書籍
1冊ですべて身につくJavaScript入門講座
総合評価
( 5 )
メリット
  • 誰でも分かるように嚙み砕いて説明してくれる
  • アニメーションの知識が深く学べる
  • 1つのWebサイトを作りながら学べる
先輩くん

Amazon Kindle Unlimitedに登録すると、月額980円で読み放題だからオススメだよ!

後輩ちゃん

初回30日間は無料だから、まだ登録したことのない人はぜひ試してみてね!

全プログラマー必見!
変数名/関数名にもう悩まない!
リーダブルコード
総合評価
( 5 )
メリット
  • 美しいコードが書けるが自然と書けるようになる
  • 他の開発者が理解しやすいコードになる
著:Dustin Boswell, 著:Trevor Foucher, 解説:須藤 功平, 翻訳:角 征典
¥2,640 (2023/07/23 02:48時点 | Amazon調べ)
目次

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ではなくなっていることが原因です。

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

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次