レッスンに戻る

クラスはオブジェクトを拡張しますか?

重要度: 3

ご存じのように、すべてのオブジェクトは通常Object.prototypeから継承され、hasOwnPropertyなどの「ジェネリック」なオブジェクトメソッドにアクセスできます。

たとえば

class Rabbit {
  constructor(name) {
    this.name = name;
  }
}

let rabbit = new Rabbit("Rab");

// hasOwnProperty method is from Object.prototype
alert( rabbit.hasOwnProperty('name') ); // true

ただし、明示的に「class Rabbit extends Object」のように指定すると、"class Rabbit"という簡単な指定とは異なる結果になりますか?

違いは何ですか?

以下にそのようなコードの例を示します(機能しません - なぜですか? 修正してください)

class Rabbit extends Object {
  constructor(name) {
    this.name = name;
  }
}

let rabbit = new Rabbit("Rab");

alert( rabbit.hasOwnProperty('name') ); // Error

まず、後者のコードが機能しない理由を見てみましょう。

その理由は、実行しようとすると明らかになります。継承クラスのコンストラクターはsuper()を呼び出す必要があります。そうでなければ、「this」は「定義」されません。

そこで修正版を次に示します。

class Rabbit extends Object {
  constructor(name) {
    super(); // need to call the parent constructor when inheriting
    this.name = name;
  }
}

let rabbit = new Rabbit("Rab");

alert( rabbit.hasOwnProperty('name') ); // true

しかし、まだ全部ではありません。

修正した後でも、「class Rabbit extends Object」とclass Rabbitとの間には重要な違いがあります。

ご存じのように、「extends」構文は2つのプロトタイプを設定します。

  1. コンストラクター関数の「prototype」間(メソッド向け)。
  2. コンストラクター関数自体間(静的メソッド向け)。

class Rabbit extends Objectの場合、それは次のことを意味します。

class Rabbit extends Object {}

alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) true

そのため、RabbitRabbitを介して次の方法でObjectの静的メソッドへのアクセスを可能にするようになりました。

class Rabbit extends Object {}

// normally we call Object.getOwnPropertyNames
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // a,b

ただし、extends Objectがない場合、Rabbit.__proto__Objectに設定されません。

デモを次に示します。

class Rabbit {}

alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) false (!)
alert( Rabbit.__proto__ === Function.prototype ); // as any function by default

// error, no such function in Rabbit
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // Error

その場合、RabbitObjectの静的メソッドへのアクセスを提供しません。

ちなみに、Function.prototypeにもcallbindなどの「ジェネリック」な関数メソッドがあります。これらは結局のところどちらの場合でも利用できます。これは、組み込みのObjectコンストラクターの場合、Object.__proto__ === Function.prototypeであるためです。

図を次に示します。

つまり、一言で言えば、2つの違いがあります。

class Rabbit クラス Rabbit は Object を拡張
コンストラクタにsuper()を呼び出す必要がある
Rabbit.__proto__ === Function.prototype Rabbit.__proto__ === Object