カテゴリ: JavaScript 更新日: 2026/06/23

JavaScriptのコールバック関数でthisが変わる理由と初心者向けの対処法完全ガイド

JavaScriptのコールバック関数でthisが変わる理由と対処法
JavaScriptのコールバック関数でthisが変わる理由と対処法

先生と生徒の会話形式で理解しよう

生徒

「先生、JavaScriptでコールバック関数を使うと、thisの中身が思った通りじゃなくなることがあります。なぜですか?」

先生

「コールバック関数では、関数が呼ばれたときのコンテキストが変わるからです。簡単にいうと、関数が実行される場所や方法によってthisの指すものが変わるんですよ。」

生徒

「なるほど、でもどうやったら正しいthisを使えるんですか?」

先生

「いくつか方法があります。例えば、アロー関数を使う方法や、bindメソッドでthisを固定する方法などがあります。順番に見ていきましょう。」

1. thisの基本とは?

1. thisの基本とは?
1. thisの基本とは?

JavaScriptで登場するthisは、関数の中で使われる特別な変数で、現在の実行コンテキスト(関数が呼ばれたときの状況)を指します。例えばオブジェクトのメソッド内で使うと、そのオブジェクト自身を指します。


const obj = {
  name: "JavaScript",
  greet: function() {
    console.log(this.name);
  }
};

obj.greet(); // JavaScript

この例では、greetの中のthisobjを指しています。

2. コールバック関数でthisが変わる理由

2. コールバック関数でthisが変わる理由
2. コールバック関数でthisが変わる理由

コールバック関数とは、他の関数に渡して後で呼び出される関数のことです。例えば、配列のforEachやイベントリスナーなどで使われます。このとき、関数がどのオブジェクトの文脈で呼ばれるかが変わるため、thisも変化します。


const obj = {
  name: "JavaScript",
  greet: function() {
    [1,2,3].forEach(function() {
      console.log(this.name);
    });
  }
};

obj.greet(); // undefined またはグローバルオブジェクト

普通の関数では、呼び出し元がオブジェクトであっても、コールバックの中ではthisが変わってしまいます。

3. アロー関数でthisを保持する方法

3. アロー関数でthisを保持する方法
3. アロー関数でthisを保持する方法

アロー関数は、定義された場所のthisをそのまま使う特徴があります。そのため、コールバック関数でthisを保持したい場合に便利です。


const obj = {
  name: "JavaScript",
  greet: function() {
    [1,2,3].forEach(() => {
      console.log(this.name);
    });
  }
};

obj.greet(); 
// 出力:
// JavaScript
// JavaScript
// JavaScript

この例では、アロー関数を使うことでgreetthisをそのまま使っています。

4. bindメソッドでthisを固定する方法

4. bindメソッドでthisを固定する方法
4. bindメソッドでthisを固定する方法

bindメソッドを使うと、関数のthisを強制的に固定できます。これにより、コールバック関数でも意図したthisを利用できます。


const obj = {
  name: "JavaScript",
  greet: function() {
    [1,2,3].forEach(function() {
      console.log(this.name);
    }.bind(this));
  }
};

obj.greet(); 
// 出力:
// JavaScript
// JavaScript
// JavaScript

bindを使うことで、コールバック関数内でもobjを指すようになります。

5. 変数にthisを代入して使う方法

5. 変数にthisを代入して使う方法
5. 変数にthisを代入して使う方法

昔ながらの方法として、thisを別の変数に代入して、コールバック関数内で使うやり方もあります。


const obj = {
  name: "JavaScript",
  greet: function() {
    const self = this;
    [1,2,3].forEach(function() {
      console.log(self.name);
    });
  }
};

obj.greet(); 
// 出力:
// JavaScript
// JavaScript
// JavaScript

この方法も、コールバック内で正しいthisを参照する手段のひとつです。

6. イベントリスナーとthisの注意点

6. イベントリスナーとthisの注意点
6. イベントリスナーとthisの注意点

HTMLのボタンなどにイベントリスナーを付ける場合、普通の関数とアロー関数でthisの挙動が異なります。


const button = document.querySelector("button");

button.addEventListener("click", function() {
  console.log(this); // button要素
});

button.addEventListener("click", () => {
  console.log(this); // グローバルオブジェクトまたはundefined
});

アロー関数では定義場所のthisを使うため、イベント対象のボタン自体は指しません。意図した挙動に応じて使い分けましょう。

7. コールバックでthisを正しく使うポイントまとめ

7. コールバックでthisを正しく使うポイントまとめ
7. コールバックでthisを正しく使うポイントまとめ

ポイントは以下の通りです。

  • コールバック関数内のthisは呼び出し方で変わる
  • アロー関数を使うと外側のthisを保持できる
  • bindthisを固定できる
  • 昔ながらのvar self = thisも有効
  • イベントリスナーでは普通の関数とアロー関数で挙動が異なる

この理解があると、JavaScriptのコールバック関数でも安全にthisを扱えます。

8. 練習問題:thisを意図通りに使ってみよう

8. 練習問題:thisを意図通りに使ってみよう
8. 練習問題:thisを意図通りに使ってみよう

以下のコードのconsole.log"Hello JavaScript"と出力するように修正してみましょう。


const obj = {
  name: "JavaScript",
  greet: function() {
    setTimeout(function() {
      console.log(this.name);
    }, 1000);
  }
};

obj.greet();

ヒント:アロー関数に変えるか、bindを使う方法があります。

9. まとめの補足として覚えておきたいこと

9. まとめの補足として覚えておきたいこと
9. まとめの補足として覚えておきたいこと

JavaScriptでコールバック関数を使うときは、thisが変わることを前提に設計することが重要です。アロー関数やbindメソッドを使うことで、安全にthisを保持できます。また、イベントリスナーや非同期処理でも同じ考え方が使えるため、慣れるとコードのバグを減らせます。

まとめ

まとめ
まとめ

今回の記事では、JavaScriptにおけるコールバック関数でthisが変わってしまう理由と、初心者でも安全にthisを使える対処法を詳しく解説しました。まず、thisは関数が呼ばれるコンテキストによって指すオブジェクトが変わる特性があるため、コールバック関数の中では意図しないオブジェクトを参照することがあります。具体的には、配列のforEachやイベントリスナー、非同期処理の中でこの問題が頻繁に発生します。

対策として、アロー関数を使う方法、bindメソッドでthisを固定する方法、さらに昔ながらのvar self = thisのように変数に代入して使う方法があります。アロー関数は定義された場所のthisを保持するため、最も直感的で簡単な方法です。bindは関数のthisを強制的に指定できるため、より明示的に制御したい場合に便利です。古典的な方法として、selfthatといった変数にthisを代入して使用する方法も依然として有効です。

また、イベントリスナーでは通常の関数とアロー関数でthisの挙動が異なります。ボタンやフォームなどのDOM要素に対してイベントを設定する場合、通常の関数ではthisがイベント対象の要素を指し、アロー関数では定義された場所のthisを保持するためグローバルオブジェクトやundefinedを参照します。用途に応じて使い分けることが大切です。

練習問題の例では、setTimeoutのコールバック内で正しいthisを参照させるには、アロー関数に変換するかbind(this)を使うことで、意図通りに「Hello JavaScript」と出力できるようになります。このように、非同期処理やコールバック関数でのthisの挙動を理解しておくことで、JavaScriptでのバグを減らし、より安全で可読性の高いコードを書くことが可能です。

まとめると、コールバック関数でthisが変わる原因と対策を理解し、アロー関数やbind、変数への代入などの方法を使い分けることが、JavaScript初心者にとって重要なスキルです。実際のプロジェクトでも、コールバック関数やイベントリスナー、非同期処理などで必ず役立つ知識となります。

先生と生徒の振り返り会話

生徒

「先生、この記事を読んで、コールバック関数でthisが変わる理由がよくわかりました。アロー関数やbindを使うと安全にthisを扱えるのですね。」

先生

「そうです。コールバック関数では呼び出し元のコンテキストが変わるため、thisも変化します。アロー関数を使うと定義された場所のthisを保持でき、bindを使うと明示的に固定できます。」

生徒

「イベントリスナーでも違いがあると書いてありましたが、具体的にはどういうことですか?」

先生

「普通の関数ではthisはイベントが発生した要素を指しますが、アロー関数では定義された場所のthisを保持するため、意図した挙動にならないことがあります。用途に応じて使い分けることが大切です。」

生徒

「なるほど、練習問題のsetTimeoutの例では、アロー関数かbind(this)を使うと意図通り出力できるのですね。」

先生

「その通りです。非同期処理でも同じ考え方が使えますし、コールバック関数で安全にthisを扱えることが、JavaScriptの安定したプログラミングの基本になります。」

生徒

「これで、JavaScriptでのコールバック関数やイベントリスナーの中でも、正しいthisを使える自信がつきました。ありがとうございます。」

カテゴリの一覧へ
新着記事
New1
JavaScript
JavaScriptのスコープとは?ローカル変数・グローバル変数の違いと使い分け
New2
TypeScript
TypeScriptで型の合成時に発生する型エラーの対処法を徹底解説!初心者にもわかりやすく解説
New3
TypeScript
TypeScriptでAPI呼び出しをラップするユーティリティ関数の設計完全ガイド!初心者向けにAxiosやFetchの使い方を解説
New4
TypeScript
TypeScriptのMapped Typesとインターフェースの連携方法を徹底解説!初心者でも理解できる型変換の基本
人気記事
No.1
Java&Spring記事人気No1
JavaScript
JavaScriptのループで無限ループが起きる原因と対策を初心者向けに徹底解説!
No.2
Java&Spring記事人気No2
JavaScript
JavaScriptのインストール方法まとめ!Windows・Mac・Linux別にステップ解説
No.3
Java&Spring記事人気No3
JavaScript
JavaScriptの文字列の長さを取得する(lengthプロパティ)
No.4
Java&Spring記事人気No4
TypeScript
TypeScriptのファイル分割とimport/exportの基本を徹底解説!初心者でも安心のやさしい入門
No.5
Java&Spring記事人気No5
TypeScript
TypeScriptでコメントを書く正しい書き方と使い分け【初心者向けにやさしく解説】
No.6
Java&Spring記事人気No6
TypeScript
TypeScriptの始め方:開発環境の構築手順【初心者向け】
No.7
Java&Spring記事人気No7
JavaScript
JavaScriptのプリミティブ型と参照型の違いを初心者向けに解説
No.8
Java&Spring記事人気No8
TypeScript
TypeScriptでパスエイリアスを設定する方法!baseUrlとpathsでコードをスッキリ整理