6時だョ!!全員集合!!

Rails・JavaScrictを中心にアウトプットします。

2022年1月15日 JavaScript (JS Primer) 2種類のインスタンスメソッドの定義

クラスでは、2種類のインスタンスメソッドの定義方法があります。 class構文を使ったインスタンス間で共有されるプロトタイプメソッドの定義と、 インスタンスオブジェクトに対するメソッドの定義です。

これらの2つの方法を同時に使い、1つのクラスに同じ名前でメソッドを2つ定義した場合はどうなるでしょうか?

次のコードでは、ConflictClassクラスにプロトタイプメソッドとインスタンスに対して同じmethodという名前のメソッドを定義しています。

class ConflictClass {
    constructor() {
        // インスタンスオブジェクトに`method`を定義
        this.method = () => {
            console.log("インスタンスオブジェクトのメソッド");
        };
    }

    // クラスのプロトタイプメソッドとして`method`を定義
    method() {
        console.log("プロトタイプのメソッド");
    }
}

const conflict = new ConflictClass();
conflict.method(); // どちらの`method`が呼び出される?

結論から述べると、この場合はインスタンスオブジェクトに定義したmethodが呼び出されます。 このとき、インスタンスのmethodプロパティをdelete演算子で削除すると、今度はプロトタイプメソッドのmethodが呼び出されます。

class ConflictClass {
    constructor() {
        this.method = () => {
            console.log("インスタンスオブジェクトのメソッド");
        };
    }

    method() {
        console.log("プロトタイプメソッド");
    }
}

const conflict = new ConflictClass();
conflict.method(); // "インスタンスオブジェクトのメソッド"
// インスタンスの`method`プロパティを削除
delete conflict.method;
conflict.method(); // "プロトタイプメソッド"

呼び出し方はどちらも同じです。

インスタンス.メソッド名()

この実行結果から次のことがわかります。

プロトタイプメソッドとインスタンスオブジェクトのメソッドは上書きされずにどちらも定義されている
インスタンスオブジェクトのメソッドがプロトタイプオブジェクトのメソッドよりも優先して呼ばれている
どちらも注意深く意識しないと気づきにくいですが、この挙動はJavaScriptの重要な仕組みであるため理解することは重要です。

この挙動はプロトタイプオブジェクトと呼ばれる特殊なオブジェクトとプロトタイプチェーンと呼ばれる仕組みで成り立っています。 どちらもプロトタイプとついていることからわかるように、2つで1組のような仕組みです。

このセクションでは、プロトタイプオブジェクトとプロトタイプチェーンとはどのような仕組みなのかを見ていきます。

クラスの役割(復習)

クラスは”インスタンスを初期化する場所”という役割を持っています。
したがって、クラスは直接呼び出すことが出来ません。

  • クラスのコンストラクタは初期化する処理を書く場所であるため、returnなどで値を返すべきではありません。
  • new演算子を用いてインスタンス化します。

コンストラクタ(復習)

クラスは必ずコンストラクタを持ち、constructorという名前のメソッドとして定義します。

  • constructorメソッドに定義した処理は、クラスをインスタンス化したときに自動的に呼び出されます。
  • コンストラクタ関数の中で使われるthisは生成したインスタンスオブジェクトを指します。

プロトタイプメソッドとインスタンスオブジェクトのインスタンスメソッドの違いのまとめ (復習)

プロトタイプメソッド

  • コンストラクタ関数外でメソッドの短縮記法で定義します。

インスタンスオブジェクトのインスタンスメソッド

  • コンストラクタ関数内のthis にメソッドを定義します。

参考

JS primer 2種類のインスタンスメソッドの定義