2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaScriptのthisバインディングを設計で制す:暗黙・明示・アロー関数の本質と選定戦略

Posted at

概要

JavaScriptにおける this の挙動は、実行時の呼び出し方によって決まるという点で、他言語とは一線を画す。
つまり this は、定義ではなく呼び出しによって決定される

以下のような状況において、this の設計がバグの温床になる:

  • コールバックで this が失われる
  • メソッドの this が意図しないオブジェクトになる
  • bind() を忘れて関数が壊れる
  • アロー関数と通常関数が混在して挙動が読めない

この記事では、this の挙動を完全に制御するために、暗黙的・明示的・アロー関数の使い分け戦略を提示する。


thisの決定ルール

① new キーワードが使われている? → thisは新しいインスタンス
② 明示的に bind/call/apply? → thisは指定された値
③ オブジェクトからの呼び出し? → thisはそのオブジェクト
④ アロー関数? → 外側のthisを継承
⑤ 上記いずれもなし → thisはグローバル(strictなら undefined)

1. 暗黙的バインディング(呼び出し元に依存)

const user = {
  name: 'Toto',
  greet() {
    return `Hello, ${this.name}`;
  }
};

user.greet(); // Hello, Toto

thisuser にバインドされる


❌ 呼び出し方が変わると this が消える

const fn = user.greet;
fn(); // ❌ undefined(または global の name)

2. 明示的バインディング:bind / call / apply

function greet() {
  return `Hello, ${this.name}`;
}

const user = { name: 'Toto' };

greet.call(user);  // Hello, Toto
greet.apply(user); // Hello, Toto

const bound = greet.bind(user);
bound();           // Hello, Toto

✅ 使い分け

メソッド 引数の渡し方 実行タイミング
call 値をカンマで並べて渡す 即時
apply 引数を配列で渡す 即時
bind 引数を保存して返す関数 遅延(再実行)

3. アロー関数によるバインディングの固定

const obj = {
  name: 'Toto',
  greet: () => {
    console.log(this.name);
  }
};

obj.greet(); // ❌ undefined(thisはグローバル)

// 正しい使い方
class Button {
  constructor(label) {
    this.label = label;
    this.onClick = () => {
      console.log(this.label); // ✅ 常にインスタンスのthis
    };
  }
}

→ アロー関数は this定義時に外側から自動的に継承する


this に関する典型的なバグ例

❌ setTimeoutで this が失われる

function Timer() {
  this.seconds = 0;
  setInterval(function () {
    this.seconds++; // ❌ this はグローバル
  }, 1000);
}

→ ✅ 解決策:アロー関数 or bind

setInterval(() => this.seconds++, 1000);

設計で選ぶ this バインディング戦略

シーン 推奨構文 理由
コールバックでthis保持 アロー関数 スコープ継承で安全
メソッド定義 通常関数(宣言/式) 呼び出し元バインド
再利用可能な関数 bind 明示的にバインド
setTimeout / setInterval での this アロー関数 or bind 暗黙バインディングは破綻する

thisを完全に理解する一問一答

const obj = {
  val: 42,
  method() {
    return this.val;
  }
};

const f = obj.method;
f();             // ❌ undefined
obj.method();    // ✅ 42
f.call(obj);     // ✅ 42
const b = obj.method.bind(obj);
b();             // ✅ 42

結語

JavaScriptの this は「文法的に定まるもの」ではなく、「設計的に定義するもの」である。

  • function=> かではなく、“どこで実行されるか”が重要
  • this を失わない設計をすることは、“コードの一貫性”を保証するということ
  • 明示(bind)・継承(arrow)・委譲(call/apply)を意図的に選び分けることが重要

「なぜ this をこう扱ったのか」を説明できる設計者が、JavaScriptを制する。

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?