概要
JavaScriptを学習、理解を深めるため「JavaScript Primer 迷わないための入門書」を読み、
理解した内容等を記載していく。
「【JavaScript】JavaScript入門一覧」に他の記事をまとめています。
この記事で理解できること
- プロトタイプメソッド、インスタンスメソッドの違い
- プロトタイプイオブジェクト、プロトタイプチェーンの仕組み
プロトタイプメソッドとインスタンスメソッドの違い
当関連記事「クラス②、③」で記載したプロトタイプメソッドとインスタンスメソッドには以下のような特徴がある。
プロトタイプメソッド
-
クラス
に定義したメソッド。 - メソッドを
プロトタイプオブジェクト
という特殊なオブジェクトに定義する。
インスタンスメソッド
-
クラスフィールド
に定義したメソッド。 - クラスの
インスタンス
に対してメソッドを定義する。
class Person {
name;
constructor(name) {
this.name = name;
}
// クラスフィールドに定義したメソッド = インスタンスメソッド
greeting = () => {
console.log(`${this.name}さん、こんにちは`)
}
// クラスに定義したメソッド = プロトタイプメソッド
callName() {
console.log(this.name);
}
}
const personA = new Person("Taro");
personA.greeting(); // => Taroさん、こんにちは
console.log(personA.callName()); // => Taro
プロトタイプメソッドとインスタンスメソッドの優先順位
プロトタイプメソッドとインスタンスメソッドが理解できたところで、
同名のプロトタイプメソッド
とインスタンスメソッド
が存在する場合、どのような挙動となるのか確認する。
- 結論を書くと
インスタンスメソッド
が優先的呼び出される。 - また、インスタンスメソッドがプロトタイプメソッドを上書きするわけでなく、どちらも定義されている。
class Person {
name;
constructor(name) {
this.name = name;
}
// インスタンスメソッド
greeting = () => {
console.log(`(インスタンスメソッド)${this.name}さん、こんにちは`);
}
// プロトタイプメソッド
greeting() {
console.log(`(プロトタイプメソッド)${this.name}さん、こんにちは`);
}
}
const personA = new Person("Taro");
// インスタンスメソッドが優先的に呼び出されている
personA.greeting(); // => (インスタンスメソッド)Taroさん、こんにちは
これらの挙動についはプロトタイプオブジェクト
とプロトタイプチェーン
という仕組みが関係している。
プロトタイプオブジェクト
-
prototypeプロパティ
に自動的に作成される特殊なオブジェクト(それが『プロトタイプオブジェクト
』ややこしい..) - class構文を用いたクラスに定義したメソッドは、
プロトタイプオブジェクトのプロパティ
として定義される。
class Person {
// このメソッドは、プロトタイプオブジェクトのプロパティとして定義される
greeting() { }
}
プロトタイプチェーン
- インスタンスから
プロトタイプメソッド
を呼び出せる仕組み。 - 以下の2つの処理から成り立つ
- インスタンス作成時
- インスタンスが持つ内部プロパティ[[Prototype]]へプロトタイプオブジェクトの参照を保存する処理
- インスタンスのプロパティ参照時
- インスタンスが持つ内部プロパティ[[Prototype]]まで探索する処理
- インスタンス作成時
class sampleClass {
// プロトタイプメソッド
greeting() {
console.log("こんにちは");
}
}
const instance = new sampleClass();
// インスタンスからプロトタイプメソッドを呼び出せる
// 裏側にはプロトタイプチェーンという仕組みがある
instance.greeting(); // => こんにちは
インスタンス作成とプロトタイプチェーン
- クラスからnew演算子でインスタンスを作成する際、インスタンスにはクラスの
プロトタイプオブジェクトへの参照
が保存される。 - 保存先としては、インスタンスオブジェクトの
[[Prototype]]
という内部プロパティに保存される。 -
[[Prototype]]
は通常のプロパティのようにアクセスできないため、Object.getPrototypeOf
メソッドで取得できる。
// インスタンスはどのクラスから作られたかやそのクラスのプロトタイプオブジェクトを知っている
プロパティの参照とプロトタイプチェーン
- オブジェクトがプロパティを探索するときは次のような順番で、それぞれのオブジェクトを調べる。
- 1.オブジェクト自身
- 2.オブジェクトの[[Prototype]]の参照先(プロトタイプオブジェクト)
- 3.それでも無かった場合、
undefined
が返される。
- この内部へと順番に探す仕組みを
プロトタイプチェーン
と呼ぶ。
class sampleClass {
// プロトタイプメソッド
greeting() {
console.log("こんにちは");
}
}
const instance = new sampleClass();
instance.greeting(); // => こんにちは
/**
* greetingメソッドが呼び出されるまでの流れ
*
* ①インスタンス(instance)内を探す -> 存在しない
* ②インスタンスの[[Prototype]]内部プロパティを参照する(プロトタイプオブジェクト) -> プロトタイプメソッドに存在する
* ③プロトタイプメソッドgreetingが呼び出されている
*/