Loading
  • LIGHT

  • DARK

ROUTE

ルートゼロの
アクティビティ

JavaScript thisの違い・バグ事例7選|アロー関数やbindの迷わない使い分け

3

「this、思った通りに動いてくれない…」——こんなモヤモヤ、開発現場で何度も経験しませんか?
通常関数やアロー関数クラスbind。どれも“this”の参照先が微妙に違い、バグや手戻り、レビュー指摘の“元凶”になりがちです。
なぜこんなに複雑? どう選べば安全?
私たちが今すぐ腹落ちできるよう、「仕組み → ミス例 → 解決策」を短く分解して解説します。

  • thisの基本仕様・違いを体系的に整理
  • バグ・手戻りを防ぐための現場ノウハウ
  • チームレビューや教育にも使えるチェックリスト

用語解説:this
JavaScriptで関数やメソッドが参照する「実行中のオブジェクト」。呼び出し方によって指すものが変わる。

用語解説:アロー関数
ES6で導入された短い記法の関数。定義時の外側スコープのthisを参照し、通常の関数とは挙動が異なる。

用語解説:bind
関数のthisを特定の値に固定するためのメソッド。新しい関数を返す。

用語解説:クラス
ES6以降で使えるオブジェクト設計の仕組み。インスタンス生成や継承が可能。

1. なぜJavaScriptのthisは迷いやすい?現場あるあるの混乱

「thisがundefined?」
「イベント内でthisが期待通りじゃない…」

実際、現場でこんな失敗がよく起きています。

  • 関数やメソッドの呼び出し方でthisがグローバルオブジェクトやundefinedになる
  • コールバック・イベントリスナーでthisが“変化”する
  • アロー関数でthisが“外側”を参照してバグ発生
  • クラス継承やプロトタイプチェーンで挙動が読みにくくなる

こうした混乱の背景には、thisが「呼び出し方」で決まるというJavaScript独特の仕様があります。

(「undefined」やthisの混乱については『なぜ「undefined」が出る?原因と解決法10選|JavaScript のデバッグに効く実例集』もご参照ください)


2. JavaScriptのthisとは?仕組みと決まり方

thisは、関数やメソッドの「呼び出し方」によって自動的に値が決まります。

  • グローバル呼び出し:通常関数を直接呼ぶとthisはグローバルオブジェクト(ブラウザならwindow、厳格モードはundefined)
  • オブジェクトのメソッド呼び出し:オブジェクトのメソッドなら、そのオブジェクト自身
  • コンストラクタ(new):新しいインスタンス自身
  • 明示的なbind/call/apply:指定した値
  • アロー関数:定義時の“外側スコープ”のthisをそのまま使う(変化しない)

「thisはどこを指すのか?」は呼び出し方ごとに整理して覚えましょう。

(letやvarの違いによるthisの混乱については『図解でわかる! JavaScript初心者がハマる letとvarの違いを徹底解説|現場での注意点まで完全対応』もご参照ください)


3. 構文別thisの違いと使い分け【表&コード例】

■ 通常関数 vs アロー関数の“this”違い

通常関数は「呼び出し元」、アロー関数は「定義時の外側」を参照します。

日常生活の例え:
「通常関数」は“誰が呼ぶか”で自分(this)が変わるイメージ。
例えば「家で『ご飯食べる』と言えば自分の家で食べる」、「友達の家で『ご飯食べる』と言えば友達の家で食べる」ように、呼び出し元によって“自分”が変わります。
一方「アロー関数」は“どこで決めたか”が基準。
例えば「お母さんが『ご飯食べる』と言ったら、いつ誰が呼んでも“お母さん”がご飯を食べる」ように、定義した時点の“自分”がずっと使われます。


const obj = {
  value: 42,
  normalFunc: function() { return this.value; },
  arrowFunc: () => this.value
};
// obj.normalFunc() → 42
// obj.arrowFunc() → undefined
  

コールバックやイベントリスナーでは、アロー関数だとthisが想定外になることが多いので注意!

■ bind/call/applyでthisをコントロール

  • bind:thisを“固定”した新しい関数を返す
  • call/apply:その場でthisを指定して関数実行(引数の渡し方が違う)

イベントリスナーで「thisがバグる」場合、bindで明示的に固定するのが定番の対策です。

■ クラス・継承・TypeScript環境でのthis

クラス(ES6以降)では、通常メソッドのthisはインスタンス自身ですが、コールバックとして渡すとthisが失われることが。
TypeScriptではthisの型安全も重要なので、設計段階からthisの流れを意識しましょう。

(TypeScriptやクラス設計の基礎については『TypeScriptとは?JavaScriptとの違いを初心者向けにわかりやすく解説』もご参照ください)


4. コールバック・イベント・非同期でのthisバグと対策

現場で本当に多いのが、コールバックやsetTimeout、イベントリスナーでthisが変化するパターン。

あるあるバグ例

  • setTimeout内でthisがグローバルやundefinedになる
  • イベントリスナーでthisが要素以外を参照

解決法

  • アロー関数で外側のthisを「捕捉」
  • bindでthisを明示的に固定
  • クラスならconstructor内でbindを仕込む

「thisをどこで束縛するか?」をチームで明文化しておくと安心です。

(コールバックや非同期処理の詳細は『JavaScriptのコールバックがわからない?アニメーション実例でやさしく解説!』もご参照ください)


5. 受託・SES現場で本当にあったthisバグとリファクタ

現場で頻発するのは、クラスのメソッドをイベントリスナーなどにそのまま渡してthisが失われるパターン。

リファクタ例

  • 誤:button.addEventListener(‘click’, this.handleClick);
  • 正:button.addEventListener(‘click’, this.handleClick.bind(this));
    またはthis.handleClick = this.handleClick.bind(this);をconstructorで実行

「イベントに渡すときは必ずthisを固定」
こうしたルールをプロジェクトで共有し、再発防止につなげましょう。


6. チーム開発で役立つthisチェックリスト&レビュー観点

バグや手戻りを減らすため、コードレビューで次を必ずチェック!

  • コールバック・イベントでthisが想定通りか
  • アロー関数/通常関数の選択が適切か
  • クラスメソッドのthisが“失われて”いないか
  • TypeScriptでthisの型が安全か

レビュー時、「この関数のthisは何を指している?」とチーム内で確認する文化をつくるのもおすすめです。


7. よくある疑問Q&A

  • Q1. JavaScriptのthisはなぜ状況ごとに変わるの?
    A. 呼び出し方ごとにthisが自動で変わる仕様だからです。
  • Q2. アロー関数でthisが想定外になるのはなぜ?
    A. アロー関数は定義時の外側スコープのthisを参照し、オブジェクトメソッドには向きません。
  • Q3. bind/call/applyの違いは?
    A. bindは新しい関数、call/applyは即時実行。どれもthisを指定できます。
  • Q4. クラス継承でのthis注意点は?
    A. メソッドをコールバックで渡すとthisが失われやすいのでbindやアロー関数で工夫を。
  • Q5. コールバックやsetTimeoutでthisが変わる理由は?
    A. 呼び出し元が異なるため、thisが思わぬ値に変化します。
  • Q6. イベントリスナーでthisを意図通り扱うには?
    A. bindやアロー関数で固定しましょう。
  • Q7. チームでthis誤用を減らすコツは?
    A. チェックリストやペアプロ、レビュー時の確認が有効です。

まとめ:this迷子から抜け出すために

thisは一見シンプルですが、構文や場面ごとに参照先が激変します。
今回ご紹介した比較表やコード例、チェックリストを現場に持ち帰り、日々の開発で「this迷子」を減らしていきましょう。
ぜひコードをコピペして、まずは動かしてみてください。


もっとルートゼロを知りたいなら

DISCOVER MORE