豆知識・お役立ち情報

クリエイター・プログラマーを目指している人のためのメディアくりぷろメディア-クリエイター・プログラマーを目指している人のためのメディア

2021.10.19更新

JavaScriptのthisで気を付けること

JavaScriptのthisで気を付けること

【JavaScriptのthisで気を付けること】コンストラクターのthisと関数のthisは違うものを表す。

JavaScriptのthisはプログラムの文脈によって参照先が変わります
その時、その時で、thisが表すものが変わる、ということです。

特にわかりづらいなぁと思ったのは、コンストラクターを実行したときのthisと関数で実行したときのthisの違いです。

関数グローバルオブジェクト(Strictモードではundefinedになる)
コンストラクター生成されたインスタンス

どこで使用するかで参照先(内容)が変化してしまうという点だけでも、わかりづいらいthisなのです。

ですが、JavaScriptの場合はもっと問題が複雑化することがあります。

JavaScriptの言語の特性上、コンストラクターを関数として呼び出せる、という点が、特にややこしいです。

実行しているプログラムは同じなのに、実行する方法がコンストラクターとして実行しているのか、関数として実行しているのかでthisの内容が変わるのです。

文章で見てもわかりにくいので、実際にコードを見てみましょう!

ES2015より前のJavaScriptでクラスを定義し、コンストラクターを実行したときのthis

var Person = function (name, age) {
      this.name = name;
      this.age = age;
    }

ES2015より前のJavaScriptでクラスを定義するには、functionを使って定義します。

上記の例はnameとageを引数として受け取り、それぞれプロパティに値をセットするPersonクラスを定義しています。

このPersonクラスをインスタンス化するには、次のように記述します。

 var p_taro = new Person("太郎", 10);

new演算子を使ってインスタンス化すると、Personクラスので定義されているfunctionは、コンストラクターとして実行されます。

なので、

var Person = function (name, age) {
      this.name = name;
      this.age = age;
    }

の2行のthisは、生成されたインスタンスのプロパティを指すことになり、それぞれ値がインスタンスのプロパティの値としてセットされます。

   console.log(p_taro.name);//太郎

を実行すれば、当然、Personクラスのインスタンスであるp_taroのnameプロパティが参照されて、「太郎」と表示されます。

コンストラクターではなく、関数として実行したときのthis

さて、先ほども書きましたが、JavaScriptはコンストラクターを関数として実行することもできます。
先ほどの例でいえば、new演算子を使わず、関数を実行する要領でPersonを実行できるのです。

var p_hana = Person("はな", 12);

p_hanaにはPersonを実行した結果が代入されるのですが、この後、

 console.log(p_hana.name);

と実行すると、エラーとなってしまいます。undefinedです。

これは、コンストラクターを関数として実行しているために、

var Person = function (name, age) {
      this.name = name;
      this.age = age;
    }

の2行のthisがグローバルオブジェクトを参照するようになり、グローバルオブジェクトのnameとageとして値がセットされてしまいます。

試しに、

console.log(name);

と実行してみると、グローバルnameが参照されるため「はな」と表示されます。

まとめ

プログラム全体をもう一度掲載しておきましょう。
コメントで結果も入力しておきますので、最後に確認してみてください。

var Person = function (name, age) {
      this.name = name;
      this.age = age;
    }

    var p_taro = new Person("太郎", 10);
    var p_hana = Person("はな", 12);

    console.log(p_taro.name);	//太郎
    console.log(name);	//はな
    console.log(p_hana.name);/	/undefinedとなり、エラー

Javaなどのプログラミングを学んだ場合、コンストラクターを関数として実行するという点にぴんとこない方も多いと思うのですが、JavaScriptのクラスは少し特殊なので気を付けるべき点があります。

またthisも独特な変数なので、プログラムが思わぬ動作をした場合は、thisやクラスの仕様を調べてみると、意外と原因が見つかったりします。