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

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

2022年1月8日 JavaScript (JS Primer) クラスのプロトタイプメソッドの定義

クラスのインスタンスに対してメソッドを定義する

前回はプロトタイプメソッドにメソッドを定義したケースを学習しましたが、 今回はインスタンスオブジェクトにメソッドを定義した場合についてまとめていきます。

下のコード例ではCounterクラスのコンストラクタ関数で、インスタンスオブジェクトにincrementメソッドを定義しています。

class Counter {
    constructor() {
        this.count = 0;
        this.increment = () => {
            this.count++;
        };
    }
}
const counterA = new Counter();
const counterB = new Counter();
// `counterA.increment()`のベースオブジェクトは`counterA`インスタンス
counterA.increment();
// 各インスタンスの持つプロパティ(状態)は異なる
console.log(counterA.count); // => 1
console.log(counterB.count); // => 0

前回ではclass内でconstructor()とは別にメソッドを定義していましたが、今回はconstructor()内でthisに対してメソッドを定義しています。

呼び出し方は前回と同じです。

counterA.increment();

今回の方法で定義したincrementメソッドはインスタンスから呼び出せるため、インスタンスメソッドと言えます。

しかし、インスタンスオブジェクトに定義したincrementメソッドはプロトタイプメソッドではありません。

異なる点を2点、挙げます。

①各インスタンスオブジェクトのメソッドの参照先は異なる

インスタンス間で共有できるメソッドをプロトタイプメソッドと呼びますが、インスタンスオブジェクトにメソッドを定義すると、共有できるメソッドではなくなってしまいます。

インスタンス間の共有 インスタンスから呼び出せる
プロトタイプメソッド(インスタンスメソッド) ⭕️ ⭕️
インスタンスメソッド(コンスタラクタ関数内のthisにメソッドを定義した場合) ⭕️

プロトタイプメソッドとして定義していた場合trueになっていた例ですが、今回の例では下のようにfalseになります。

console.log(counterA.increment === counterB.increment); // => false

②Arrow Functionが利用できる(thisにメソッドを定義する場合)

Arrow Functionにはthisが静的に決まるという性質があり、Arrow Functionで定義したメソッドはどのような呼び出し方をしても、常にインスタンスを参照します。 下の例を見るとメソッドにおけるthisの参照先がインスタンスに固定されているためmethodを呼び出すとinstanceを参照出来ることがわかります。

"use strict";
class ArrowClass {
    constructor() {
        // コンストラクタでの`this`は常にインスタンス
        this.method = () => {
            // Arrow Functionにおける`this`は静的に決まる
            // そのため`this`は常にインスタンスを参照する
            return this;
        };
    }
}
const instance = new ArrowClass();
const method = instance.method;
// 呼び出し方法(ベースオブジェクト)に依存しないため、`this`がインスタンスを参照する
console.log(method()); // => instance

一方、プロトタイプメソッドでは、通常のthisの挙動と同様にベースオブジェクトを参照するので、呼び出し時にメソッドでなければundefined になってしまいます。

"use strict";
class PrototypeClass {
    method() {
        // `this`はベースオブジェクトを参照する
        return this;
    };
}
const instance = new PrototypeClass();
const method = instance.method;
// ベースオブジェクトはundefined
console.log(method()); // => undefined

復習

  • thisは呼び出し時に定義されるため、基本的に呼び出し時にメソッドでなければundefinedになってしまいます。

メモ

  • クラス内でthisにメソッドを定義した場合、それはインスタンスメソッドと言えるが、プロトタイプメソッドではない。
  • プロトタイプメソッドは各インスタンスで共有出来るメソッドを指す。

参考

クラスのインスタンスに対してメソッドを定義する