JavaScript

thisを使用した関数呼び出しでエラーになった話【JavaScript】

javascript関数とアロー関数におけるthis

JavaScriptでクラス、メソッドを作成し、いざ実行すると。

Uncaught TypeError: this.x is not a function at ~ 」とエラーが表示されてしまった。
このエラーは、見て分かる通り、関数を呼び出したが、定義されていない。というエラーになります。

でも、しっかりメソッドは定義しているのに、なぜかエラーが出てしまう。
そういう時に原因と思われるところを解説したいと思います。

どういう状況でエラーがでるか?

まずは、どういった状況でエラーが出るかを見てみましょう。
そのためのテストとして、物凄く簡単なクラスを作成しました。

//テストクラス
class testClass {

  //コンストラクタで、ボタンにイベントをセット
  constructor() {
    this.message();      //・・・・・・【 1 】
    document.getElementById("button1").addEventListener("click",function() {
      this.message();    //・・・・・・【 2 】
    })
    document.getElementById("button2").addEventListener("click",()=> {
      this.message();    //・・・・・・【 3 】
    })
  }

 //メッセージを表示するメソッド
 message() {
    console.log("作成成功")
 }
}

//クラス作成
new testClass();

前述のクラスの簡単な説明をします。
・「testClass」クラス
・コンストラクタと「massage」メソッドを持つ。
・インスタンスが作られると、ボタン1と2それぞれに「massage」メソッドを実行するクリックイベントを設定する。

どのメソッド呼び出しがエラーになるか?

さて、本題ですが、【1】~【3】 まで、「massage」メソッドを3回呼び出しています。
どれがエラーになると思いますか?

正解は、【2】の「button1」のクリックイベントでの呼び出しです。

thisが表しているものが違う

これは、functionで宣言した関数と、アロー関数で宣言したクリックイベントの「this」が表しているものが違うためです。

ためしに、それぞれの「this」をコンソールに表示してみます。

constructor() {

  console.log(this)  //・・・・・・【 1 】
  document.getElementById("button1").addEventListener("click", function () {
    console.log(this)//・・・・・・【 2 】
  })
  document.getElementById("button2").addEventListener("click", () => {
    console.log(this)//・・・・・・【 3 】
  })
}

その結果が、以下のようになります。

・【1】コンストラクタの「this」→作成したインスタンス自身
【2】functionで作成した関数の「this」→クリックしたボタンそのもの。
・【3】アロー関数の「this」→作成したインスタンス自身

ということで、イベントリスナー内での「this」はクリックしたボタンそのものを表していたために、「Uncaught TypeError: this.x is not a function at ~ 」のエラーが出ていたんですね。

JavaScriptの「this」は呼び出した場所によって、指し示すものが異なります。

エラーの解消方法

エラーの原因は分かりましたが、これを解消していかなければなりません。
方法は主に二つになります。

アロー関数を使用する

前述の通りアロー関数で宣言したイベントの「this」は、インスタンス自身を指し示めてしていました。
アロー関数で書けばスマートに書けますし、こちらが簡単だと思います。

bind() メソッドを使用する

bindメソッドとは、「this」の値を紐づけ、新しい関数を生成するためのメソッドです。
bindメソッドが呼ばれると、引数に指定した「this」の値を持った新しい関数を生成できます。

実際に使用してみます。
イベントリスナーのコールバック関数に「bind(this)」を設定しました。
この状態でもう一度コンソールを確認します。

  document.getElementById("button1").addEventListener("click", function () {
    console.log(this)
  }.bind(this))

「bind()」を使用した結果、通常のfunctionの「this」もインスタンスを示すようになりました。

まとめ

以上 javaScriptでの関数呼び出しエラーについての対処法でした。
javaScriptのthisは呼び出した場所や方法で内容が変化するので、取っつきづらいかもしれません。
今度また、まとめて記事にしたいと思います。

-JavaScript
-, ,