JavaScriptの開発において「this」というキーワードは、最も混乱を招きやすい要素の一つです。
特にプログラミング初心者にとって、状況に応じて中身が変化するthisの振る舞いを理解することは、大きな壁となることがあります。
しかし、thisの仕組みを正しく理解すれば、コードの再利用性を高め、より柔軟なプログラムを記述できるようになります。
本記事では、2026年現在のモダンなJavaScript開発においても不可欠な、thisの基本原則と4つの決定ルールについて詳しく解説します。
JavaScriptのthisとは何か?
JavaScriptにおけるthisとは、「その関数がどのように呼び出されたか」によって中身が決まる特殊な変数のことです。
多くのオブジェクト指向言語では、thisは常にそのクラスから生成されたインスタンス自身を指します。
一方でJavaScriptのthisは、実行時のコンテキスト(文脈)に応じて動的に変化するという性質を持っています。
この「動的に変化する」という点が、JavaScriptの柔軟性を生む一方で、バグの原因にもなりやすい理由です。
JavaScriptの実行環境において、thisが参照する対象は大きく分けて4つのルールに基づいています。
これらのルールには明確な優先順位があり、それを把握することがthisマスターへの第一歩となります。
実行コンテキストとthisの関係
JavaScriptのコードが実行される際、エンジン内部では「実行コンテキスト」と呼ばれる情報が作成されます。
この実行コンテキストの中に、その場所で利用できる変数や関数の情報とともに、thisの参照先が格納されています。
グローバルスコープでthisを参照した場合、ブラウザ環境であればwindowオブジェクトを指します。
しかし、関数内部では、その関数を呼び出した「呼び出し元」がどこであるかが重要になります。
基本ルール1:デフォルトバインディング(単独の関数呼び出し)
最も基本的なルールは、オブジェクトのメソッドとしてではなく、単純な関数として呼び出した場合の挙動です。
この場合、thisはデフォルトの対象を参照するようになります。
非厳格モード(Non-strict mode)の場合
非厳格モードでは、関数内のthisはグローバルオブジェクトを参照します。
function showThis() {
console.log(this);
}
showThis();
Window { ... } (ブラウザ環境の場合)
このように、特定のオブジェクトに属さない関数として実行すると、暗黙的にグローバルが割り当てられます。
厳格モード(Strict mode)の場合
現代のJavaScript開発(ES Modulesなど)では、基本的に厳格モードが有効になっています。
厳格モードでは、意図しないグローバル汚染を防ぐため、関数内のthisはundefinedになります。
"use strict";
function showThis() {
console.log(this);
}
showThis();
undefined
この挙動を理解していないと、関数内でthis.nameのようにアクセスしようとした際にエラーが発生することになります。
基本ルール2:暗黙的バインディング(メソッドとしての呼び出し)
次に重要なのが、オブジェクトのプロパティとして定義された関数(メソッド)を呼び出す場合です。
このとき、thisはそのメソッドを保持している直前のオブジェクトを指します。
メソッド呼び出しの例
const user = {
name: "田中",
greet: function() {
console.log("こんにちは、" + this.name + "さん");
}
};
user.greet();
こんにちは、田中さん
上記のコードでは、greetメソッドがuserオブジェクトから呼び出されています。
そのため、メソッド内のthisは自動的にuserオブジェクトを参照します。
暗黙的バインディングが外れるケース
注意が必要なのは、メソッドを別の変数に代入してから呼び出した場合です。
const user = {
name: "田中",
greet: function() {
console.log(this.name);
}
};
const detachedGreet = user.greet;
detachedGreet(); // ここでバインディングが失われる
undefined (または strict mode でない場合は空文字など)
この現象は「thisの消失」と呼ばれ、コールバック関数としてメソッドを渡す際によく発生します。
detachedGreetはただの関数として呼び出されているため、ルール1(デフォルトバインディング)が適用されるからです。
基本ルール3:明示的バインディング(call, apply, bind)
開発者が意図的にthisの対象を指定したい場合には、call、apply、bindという3つのメソッドを使用します。
これらを明示的バインディングと呼びます。
callとapplyの使い方
callとapplyは、関数を即座に実行する際に第一引数へthisにしたいオブジェクトを渡します。
function introduce(age, job) {
console.log(`${this.name}は${age}歳で、職業は${job}です。`);
}
const person = { name: "佐藤" };
introduce.call(person, 25, "エンジニア");
introduce.apply(person, [25, "エンジニア"]);
佐藤は25歳で、職業はエンジニアです。
佐藤は25歳で、職業はエンジニアです。
callは引数をカンマ区切りで渡し、applyは引数を配列として渡すという違いがあります。
bindの使い方
bindは関数を実行するのではなく、thisが固定された新しい関数を返します。
const person = { name: "鈴木" };
function greet() {
console.log("私は" + this.name);
}
const boundGreet = greet.bind(person);
boundGreet();
私は鈴木
一度bindされた関数のthisは、後から変更することができません。
これはイベントリスナーやsetTimeoutの中でthisを保持したい場合に非常に便利です。
基本ルール4:newバインディング(コンストラクタ呼び出し)
JavaScriptではnew演算子を使って関数を呼び出すことで、その関数をコンストラクタ(設計図)として扱うことができます。
このとき、thisは新しく生成された空のオブジェクトを指します。
new演算子の挙動
function Player(name) {
// 内部で this = {} が作成されるイメージ
this.name = name;
this.sayHello = function() {
console.log("プレイヤー: " + this.name);
};
}
const hero = new Player("勇者");
hero.sayHello();
プレイヤー: 勇者
new演算子を使って呼び出された場合、関数の最後で暗黙的にthisが返されます。
その結果、変数heroにはthis.nameが設定されたオブジェクトが格納される仕組みです。
【重要】アロー関数におけるthisの特殊なルール
ES6(ES2015)で導入されたアロー関数(() => {})は、これまでの4つのルールとは全く異なる挙動をします。
アロー関数は自身のthisを持ちません。
レキシカル・スコープによる決定
アロー関数内のthisは、その関数が定義された場所の、外側のスコープのthisをそのまま継承します。
これを「レキシカル・ディス(Lexical this)」と呼びます。
const timer = {
count: 0,
start: function() {
// 通常の関数だとここで this が timer を指す
setTimeout(() => {
// アロー関数なので、外側の start メソッドの this を継承する
this.count++;
console.log(this.count);
}, 1000);
}
};
timer.start();
1
もしsetTimeoutの中で通常の関数(function() {})を使っていた場合、thisはグローバルオブジェクトまたはundefinedを指してしまい、エラーになります。
アロー関数の登場により、bind(this)を書く手間が大幅に削減されました。
アロー関数で解決できないケース
一方で、アロー関数をオブジェクトのメソッドとして定義すると問題が発生します。
const user = {
name: "山田",
greet: () => {
console.log(this.name); // this は user ではなく外側(window等)を指す
}
};
user.greet();
undefined
メソッドを定義する場合は、アロー関数ではなく従来の関数記法を使用するのが鉄則です。
バインディングルールの優先順位
複数のルールが重複した場合、どのルールが適用されるかには優先順位があります。
基本的には以下の順番で強くなります。
newバインディング(最強)- 明示的バインディング(
call,apply,bind) - 暗黙的バインディング(メソッド呼び出し)
- デフォルトバインディング(最弱)
例えば、bindで固定した関数をさらにnewで呼び出した場合、newによる新しいオブジェクトの生成が優先されます。
モダンJavaScriptにおけるthisの使い分け
2026年現在の開発現場では、class構文やアロー関数の普及により、thisを直接意識する機会は整理されてきました。
しかし、Reactのクラスコンポーネントのメンテナンスや、独自のライブラリ開発においては、依然としてthisの理解が必須です。
クラス構文でのthis
JavaScriptのクラスは内部的にプロトタイプベースで動いており、メソッド内のthisはインスタンスを指します。
class Counter {
constructor() {
this.value = 0;
}
increment() {
this.value++;
console.log(this.value);
}
}
const myCounter = new Counter();
myCounter.increment();
1
ただし、クラスのメソッドをイベントハンドラに渡す際は、thisが外れてしまうため、コンストラクタでのbindやクラスプロパティ(アロー関数)の利用が推奨されます。
コールバック関数での対策
forEachやmapなどの高階関数を使う際、第二引数にthisを指定できるメソッドもあります。
しかし、現在ではアロー関数を使って外側のthisをキャプチャする方法が最も一般的です。
まとめ
JavaScriptのthisは、関数が定義された場所ではなく、「どのように呼び出されたか」によって決まります。
まずは今回紹介した4つの基本ルールを暗記し、その後にアロー関数の特殊な挙動を理解するのが効率的です。
特に「メソッドとして呼び出した場合」と「単独の関数として呼び出した場合」の違いを区別できるようになれば、エラーの多くを未然に防ぐことができます。
コードを書いていてthisの挙動が怪しいと感じたら、一度ブラウザのコンソールでconsole.log(this)を実行して、現在のコンテキストを確認する癖をつけましょう。
この基礎知識があれば、複雑なフレームワークや大規模なアプリケーション開発でも、自信を持ってコードを読み書きできるようになるはずです。
JavaScriptの仕様は進化し続けていますが、このthisの根本的な仕組みは今後も変わることはありません。
一つずつ丁寧に紐解いて、JavaScriptをより深く使いこなしていきましょう。
