レッスンに戻る

クラスは Object を拡張しますか?

重要性: 5

私たちが知っている通り、すべてのオブジェクトは通常 Object.prototype を継承しており、“一般的な” オブジェクトメソッドにアクセスできます。

ここでのデモンストレーションのように:

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

let rabbit = new Rabbit("Rab");

// hasOwnProperty メソッドは Object.prototype からです
// rabbit.__proto__ === 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') ); // true

もし動かない場合、コードを直してください。

解答は2つパートがあります。

最初に、簡単な方は、継承しているクラスはコンストラクタで super() を呼ぶ必要があるということです。そうでなければ "this" が “定義済み” になりません。

なので、次のように直します:

class Rabbit extends Object {
  constructor(name) {
    super(); // 継承しているとき、親コンストラクタを呼ぶ必要があります
    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

従って、このように Rabbit 経由で Object の静的メソッドにアクセスすることができます。:

class Rabbit extends Object {}

// 通常は Object.getOwnPropertyNames と呼びます
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // a,b

また、extends を使わない場合 class Rabbit は2つ目の参照を持ちません。

比較してみてください:

class Rabbit {}

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

// エラー、Rabbit にこのような関数はありません
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // Error

シンプルな class Rabbit では Rabbit 関数は同じプロトタイプを持っています。

class Rabbit {}

// (2) の代わりに、これは正しいです:
alert( Rabbit.__proto__ === Function.prototype );

ところで、Function.prototype は “一般的な” 関数メソッドを持っています。例えば call, bind などです。それらは究極的には両方のケースで利用可能です。なぜなら、組み込みの Object コンストラクタに対して、Object.__proto__ === Function.prototype だからです。

これはその図です:

従って、まとめると2つの違いがあります。:

class Rabbit class Rabbit extends Object
コンストラクタで super() を呼ぶ必要がある
Rabbit.__proto__ === Function.prototype Rabbit.__proto__ === Object