カテゴリー
SugiBlog Webエンジニアのためのお役立ちTips

コールバック関数でのthisの扱いに注意!

この記事は最終更新日から1年以上経過しています。

JavaScriptのクラスやオブジェクトリテラルでコーディングしていて、他の言語と同じ感覚でthisキーワードを使用しているとバグが発生する可能性があります。

他の言語だとthisというとクラスやオブジェクト自身を参照するのですが、JavaScriptだと少し違って、通常は同じようにクラスやオブジェクト自身を参照してくれるのですが、コールバック関数で呼び出された場合はwindowを参照するのです。
これを知らないと意図しない動作でバグとなり、エラーが発生しますのでご注意ください。

実際にサンプルコードを踏まえて説明します。
まずはコールバック関数を実行するメソッドを含んだオブジェクトを作成します。

const exam1 = {

    a: function(callback) {
        callback();
    }

}

次に、コールバック関数を引数に与えて、先ほどのオブジェクトのメソッドを実行するためのオブジェクトを作成します。

const exam2 = {

    b: function() {
        console.log("function b!");
    },

    c: function() {
        this.b();
    },

    d: function() {
        exam1.a(exam2.c);
    }

}

実行する順番としては次の通りです。

  1. exam2.dを実行
  2. exam1.aにコールバック関数の引数としてexam2.cを渡して実行
  3. exam1.aによりexam2.cが実行される
  4. exam2.cによりthis.bが実行される

しかしながらthis.bが実行された時点で

Uncaught TypeError: this.b is not a function

というエラーが発生します。 ※this.b=exam2.b
exam2.bという関数は宣言してあるのになぜ?と思いますよね。

ここでエラーが発生する原因はexam1.aにより実行されるexam2.cの中でthisキーワードが使われていることです。
コールバックにより実行される関数の中でのthisキーワードがwindowオブジェクトを参照しているからで、windowオブジェクトにはbメソッドがないのでエラーになるのです。
ここが他の言語とは異なっています。

対応策として、アロー関数をコールバック関数として渡すことでエラーを回避できます。
exam2.dを以下のように書き換えます。

    d: function() {
        exam1.a(() => { exam2.c(); });
    }

こうすることで、thisキーワードがexam2を参照し正常に実行できるようになります。

参考URL:
https://pisuke-code.com/javascript-class-this-in-callback/

この記事がお役に立ちましたらシェアお願いします
1,712 views

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です