返回課程

類別延伸物件?

重要性: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」語法設定了兩個原型

  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 現在透過 Rabbit 提供對 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

因此,在這種情況下,Rabbit 沒有提供對 Object 的靜態方法的存取。

順帶一提,Function.prototype 也有「一般」函式方法,例如 callbind 等。它們最終在兩種情況下都可用,因為對於內建的 Object 建構函式,Object.__proto__ === Function.prototype

以下是圖片

因此,簡而言之,有兩個差異

class Rabbit class Rabbit extends Object
需要在建構函式中呼叫 super()
Rabbit.__proto__ === Function.prototype Rabbit.__proto__ === Object