LoginSignup
0

More than 1 year has passed since last update.

【JavaScript】クラス④ 〜プロトタイプオブジェクト〜

Posted at

概要

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が呼び出されている
 */

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
0