JavaScript | アロー関数のthisをやさしく理解する

JavaScript
スポンサーリンク

アロー関数のthisをやさしく理解する

アロー関数は「短く書ける関数」だけではありません。いちばんの特徴は、thisが「外側のthisに固定される(レキシカルに束縛される)」ことです。つまり、アロー関数の中でthisが何になるかは、宣言された場所のthisに依存し、呼び出し方で変わりません。


ふつうの関数とアロー関数の違い(核心)

  • ふつうの関数: 呼び出し方でthisが変わる(オブジェクトから呼べばそのオブジェクト、単独で呼べばundefinedやグローバル)。
  • アロー関数: 宣言時の「外側のスコープのthis」に固定。call/apply/bindでも変えられません。
const obj = {
  name: 'Alice',
  // ふつうの関数(メソッド)
  greet() {
    console.log(this.name); // 'Alice'
  },
  // アロー関数
  greetArrow: () => {
    console.log(this.name); // ここでのthisは「外側」。多くの環境ではundefinedかグローバル
  }
};

obj.greet();      // 'Alice'
obj.greetArrow(); // undefined(またはグローバルのname)
JavaScript
  • ポイント: オブジェクトのメソッドとしてアロー関数を使うと、期待どおりのthisになりません。

どんなときに便利?(レキシカルthisの活躍)

クラスやオブジェクトの内部でコールバックに使う

「内部のthis(インスタンス)を保ちたい」場面で、アロー関数は強力です。

class Counter {
  constructor() {
    this.value = 0;
  }
  start() {
    setInterval(() => {
      // アロー関数なので、thisはCounterインスタンスのまま固定
      this.value++;
      console.log(this.value);
    }, 1000);
  }
}

const c = new Counter();
c.start();
// 1, 2, 3 ... と動く
JavaScript
  • ラベル: レキシカル固定
    説明: setIntervalに渡した関数は後で呼ばれるが、thisが「外側のthis(Counterのインスタンス)」に固定される。

ネストした関数で外側のthisを使いたい

const timer = {
  seconds: 0,
  start() {
    const tick = () => {
      this.seconds++; // 外側(start内)のthisをそのまま使える
      console.log(this.seconds);
    };
    setInterval(tick, 1000);
  }
};
timer.start();
JavaScript
  • ラベル: 便利さ
    説明: ふつうの関数で書くとthisが変わってしまうため、bind(this)が必要になる。アロー関数なら不要。

どんなときに使わないほうがいい?(落とし穴)

オブジェクトのメソッド定義

const user = {
  name: 'Bob',
  // NG例:メソッドをアローで定義
  getName: () => this.name
};
console.log(user.getName()); // undefined
JavaScript
  • ラベル: 避ける理由
    説明: アロー関数のthisは外側(グローバル)に固定されるため、userを指さない。メソッドは通常の関数記法で。

DOMイベントのハンドラで要素をthisにしたいとき

const btn = document.querySelector('#btn');

// NG:thisでボタンを参照したいならアローは不適
btn.addEventListener('click', () => {
  console.log(this); // 外側のthis(windowなど)、ボタンではない
});

// OK:通常の関数ならthisがクリックされた要素に
btn.addEventListener('click', function() {
  console.log(this); // <button id="btn">...</button>
});
JavaScript
  • ラベル: 使い分け
    説明: 要素をthisで参照したいイベント処理は、通常の関数を使う。

call/apply/bindが効かない例

アロー関数のthisは固定されるので、後から変えられません。

const outer = { name: 'Outer' };

const arrow = () => {
  console.log(this.name); // 外側のthis(たいていundefined)
};

const normal = function() {
  console.log(this.name);
};

arrow.call({ name: 'A' });   // 変わらない → undefined
normal.call({ name: 'B' });  // 'B' に変えられる
JavaScript
  • ラベル: 不変性
    説明: bindしてもアロー関数のthisは変わらない。設計時に「外側のthisを使う」と決まっているから。

実践的なパターン集

  • クラスのプロパティとしてアロー(よく使う)
class Toggle {
  constructor() { this.on = false; }
  click = () => { this.on = !this.on; } // どこから呼んでもthisはインスタンス
}
const t = new Toggle();
const f = t.click;
f(); // 問題なくインスタンスを指す
JavaScript
  • 配列メソッドのコールバック(map/filter
const list = [1, 2, 3];
const doubled = list.map(n => n * 2);
JavaScript

ラベル: 省コード
説明: thisに依存しない小さな関数は、アローで短く書くのが合う。

  • 非同期で外側のthisを保つ
function Loader() {
  this.done = false;
}
Loader.prototype.load = function() {
  fetch('/data').then(() => {
    // アローで外側のthis(Loaderインスタンス)を保持
    this.done = true;
  });
};
JavaScript

まとめ(使い分けの指針)

  • 外側のthisを保ちたいとき: アロー関数が最適(タイマー、非同期、クラスのコールバック)。
  • オブジェクトのメソッドやイベントで要素をthisにしたいとき: 通常の関数を使う。
  • call/apply/bindでthisを切り替えたい設計: 通常の関数を使う。
  • 短いコールバックでthisに依存しない処理: アロー関数で簡潔に。

「アローは外側のthisに固定」「メソッドやイベントでthisに期待があるなら通常の関数」——この2本柱を覚えておけば、迷いません。

タイトルとURLをコピーしました