JavaScript | ES6+ 文法:関数の進化 – this の束縛差

JavaScript
スポンサーリンク

this の束縛差とは何か

this は「関数が“どのオブジェクトを対象に動くか”を指す特別な値」です。ここが重要です:従来の function は“呼び出し方”で this が決まり、アロー関数は“定義場所の this(レキシカル this)”に固定されます。この差を理解すると、イベントや非同期コールバックでの「this 迷子」を防げます。


従来の function の this(呼び出し方で決まる)

メソッド呼び出し(obj.method())

obj.method() のように“ドット左”のオブジェクトが this になります。

const counter = {
  value: 0,
  inc: function() { this.value++; }
};
counter.inc();
console.log(counter.value); // 1(this は counter)
JavaScript

単独呼び出し(関数をただ呼ぶ)

関数をそのまま呼ぶと、strict モードでは this は undefined、非 strict ではグローバル(window)になります。ここが重要です:strict を前提にして undefined になる設計にするのが安全です。

"use strict";
function f() { console.log(this); }
f(); // undefined(strict)
JavaScript

コンストラクタ呼び出し(new)

new で呼ぶと、this は“新しいインスタンス”になります。

function User(name) { this.name = name; }
const u = new User("Alice");
console.log(u.name); // "Alice"
JavaScript

明示束縛(call / apply / bind)

this を手動で指定できます。bind は“this 固定の新関数”を返します。

function show() { console.log(this.id); }
const obj = { id: 123 };
show.call(obj);    // 123
const bound = show.bind(obj);
bound();           // 123(常に obj)
JavaScript

アロー関数の this(レキシカルに“固定”)

定義場所の this をキャプチャする

アロー関数は“自分自身の this を持たず”、外側の this をそのまま使います。ここが重要です:クラス内でコールバックにすると、bind なしで意図通りに動きます。

class Counter {
  constructor() {
    this.value = 0;
    setInterval(() => { this.value++; }, 1000); // this はクラスのインスタンス
  }
}
JavaScript

メソッド定義には不向き

オブジェクトのメソッドで this を“呼び出し方に合わせたい”なら、function 記法を使います。アローだと外側の this を掴んでしまい、obj を指さなくなります。

const obj = {
  x: 0,
  inc() { this.x++; }      // 正しい(this は obj)
  // inc: () => { this.x++; } // NG(外側の this を参照)
};
JavaScript

よくある this 迷子と解決策(重要ポイントの深掘り)

メソッドを変数に取り出して呼ぶと失敗

メソッドを取り出すと“ドット左”が失われ、this が undefined になります。bind か、アローのコールバックで包んで回避します。

"use strict";
const obj = { id: 1, show() { console.log(this.id); } };

const fn = obj.show;
// fn(); // TypeError(this が undefined)

const bound = obj.show.bind(obj);
bound(); // 1(bind で固定)

// またはコールバック内でレキシカル this を使う
setTimeout(() => obj.show(), 0); // 1
JavaScript

イベントハンドラでの this

DOM の addEventListener のコールバックにおける this は“イベントの currentTarget”ではなく、strict では undefined です。必要なら event.currentTarget を使い、this 目当てで書かないのが安全です。

button.addEventListener("click", function (e) {
  console.log(e.currentTarget === button); // true
});

button.addEventListener("click", (e) => {
  console.log(e.currentTarget.id); // アローでも e を使えば安全
});
JavaScript

setTimeout / Promise での this 破綻

function を直接渡すと this が失われがち。アロー関数にして外側の this を固定するか、bind で固定します。

const view = {
  id: 42,
  render() { console.log(this.id); }
};

// 失敗例
setTimeout(view.render, 0); // TypeError(this なし)

// 解決(アローで包む)
setTimeout(() => view.render(), 0); // 42

// もしくは bind
setTimeout(view.render.bind(view), 0); // 42
JavaScript

実務での指針(いつアロー、いつ function)

コールバックはアロー、メソッドは function

非同期・配列処理・イベント登録など“外側の this を使いたい”コールバックはアロー関数が最適。オブジェクトやクラスの“メソッドとして使う”関数は function 記法で定義します。

class Timer {
  constructor() {
    this.ticks = 0;
    this.start = () => {                     // アロー:this 固定
      this.id = setInterval(() => this.ticks++, 1000);
    };
  }
  stop() {                                   // メソッド:function 記法
    clearInterval(this.id);
  }
}
JavaScript

this が必要ない設計を選ぶ

this 前提の API ではなく、引数ベースの純粋な関数に寄せると安全性とテスト容易性が上がります。ここが重要です:this を使わず、受け取った値を返す“純粋な処理”を増やす。

const toLabel = (user) => `${user.id}:${user.name.trim()}`; // this 不要の関数
JavaScript

まとめ

this の束縛差の核心は「function は呼び出し方で this が変わり、アロー関数は定義場所の this に固定される」ことです。メソッド抽出・非同期コールバック・イベント登録で this が失われやすい箇所は、アローで外側の this をキャプチャするか bind で固定する。メソッドは function 記法、コールバックはアロー、strict モードを前提にして“this なし”を安全側にする。この指針を徹底すれば、初心者でも this で迷わず意図どおりの ES6+ コードを書けます。

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