はじめに
JavaScriptを学習する上で、多くの人がつまずくのがthisの挙動です。thisの値は状況によって変わるため、予期しない動作に戸惑うことも少なくありません。
この記事では、メソッドと関数の違いから始まり、thisの決定ルール、そしてWindowオブジェクトとの関係まで、thisを理解するために必要な知識を体系的に解説します。
メソッドと関数の違い
JavaScriptにおいて、メソッドと関数は明確に区別されます。オブジェクトのキーに関数を定義した場合、それはメソッドと呼ばれます。
メソッドの定義方法
メソッドは.を使って呼び出すことができます。定義方法は2つあります。
// 方法1: functionキーワードを使う
const person = {
name: "田中",
greet: function() {
console.log("こんにちは、" + this.name + "です");
}
};
person.greet(); // "こんにちは、田中です"
// 方法2: ES6のメソッド記法(短縮記法)
const person = {
name: "田中",
greet() {
console.log("こんにちは、" + this.name + "です");
}
};
person.greet(); // "こんにちは、田中です"
どちらの方法でも同じ結果が得られますが、ES6の短縮記法の方が簡潔で読みやすいですね。
通常の関数との違い
一方、オブジェクトに属さない関数は、単に関数と呼ばれます。
function greet() {
console.log("こんにちは");
}
greet(); // "こんにちは"
thisの基本ルール
thisの値を理解する上で最も重要なのは、thisを使っている関数がどのように呼ばれたかによってthisの値が決まるという点です。
ルール1: ドットの左側のオブジェクトがthisになる
メソッドとして呼び出された場合、.の左側にあるオブジェクトがthisとして参照されます。
const person = {
name: "田中",
greet() {
console.log("こんにちは、" + this.name + "です");
}
};
person.greet(); // "こんにちは、田中です"
// この場合、thisはpersonオブジェクトを指す
ルール2: 関数を変数に入れて呼び出すときは注意が必要
メソッドを変数に代入してから呼び出すと、thisの参照先が変わってしまいます。
const person = {
name: "田中",
greet() {
console.log("こんにちは、" + this.name + "です");
}
};
// メソッドを変数に代入
const greetFunction = person.greet;
greetFunction(); // "こんにちは、undefinedです"
// この場合、thisはWindowオブジェクトを指す
なぜこのような動作になるのでしょうか。それはWindowオブジェクトの存在が関係しています。
Windowオブジェクトとthisの関係
JavaScriptには、Windowという特別なグローバルオブジェクトが存在します。
Windowオブジェクトの特徴
JavaScriptで作成したあらゆるグローバルなオブジェクトや関数は、実はWindowオブジェクトのプロパティとして定義されています。Windowは省略することができるため、普段は見えない部分にあります。
// グローバル変数の定義
var globalName = "山田";
// 実際には以下と同じ
// window.globalName = "山田";
console.log(globalName); // "山田"
console.log(window.globalName); // "山田"(同じ値)
thisがWindowになるケース
.の左側にオブジェクトがない状態で関数を呼び出すと、thisはWindowオブジェクトを指します。
const person = {
name: "田中",
greet() {
console.log("こんにちは、" + this.name + "です");
}
};
const greetFunction = person.greet;
// greetFunctionの呼び出しは、実は以下と同じ
// window.greetFunction();
greetFunction(); // "こんにちは、undefinedです"
// thisはWindowを指すため、window.nameを参照しようとする
// window.nameは定義されていないのでundefinedになる
よくあるthisの落とし穴と対処法
問題: コールバック関数内でのthis
メソッドをコールバック関数として渡すと、thisの参照が失われます。
const person = {
name: "田中",
greet() {
console.log("こんにちは、" + this.name + "です");
}
};
setTimeout(person.greet, 1000); // "こんにちは、undefinedです"
対処法1: アロー関数を使う
アロー関数はthisを持たず、外側のスコープのthisを継承します。
const person = {
name: "田中",
greet() {
setTimeout(() => {
console.log("こんにちは、" + this.name + "です");
}, 1000);
}
};
person.greet(); // 1秒後に "こんにちは、田中です"
対処法2: bindメソッドを使う
bindメソッドを使うと、thisを固定した新しい関数を作成できます。
const person = {
name: "田中",
greet() {
console.log("こんにちは、" + this.name + "です");
}
};
const boundGreet = person.greet.bind(person);
setTimeout(boundGreet, 1000); // 1秒後に "こんにちは、田中です"
thisの決定ルールまとめ
まとめ
JavaScriptのthisは、関数がどのように呼び出されたかによって値が決まります。
- メソッドとして呼び出された場合、
.の左側のオブジェクトがthisになる - 通常の関数として呼び出された場合、
thisはWindowオブジェクトを指す - メソッドを変数に代入して呼び出すときは、
thisの参照が変わるため注意が必要 - Windowオブジェクトはすべてのグローバル変数や関数の親であり、通常は省略されている
thisの挙動を理解することで、予期しないバグを防ぎ、より堅牢なコードを書けるようになります。特にコールバック関数を使う場合は、アロー関数やbindメソッドを活用して、thisの参照を適切に管理しましょう。