返回課程

使用相同的建構函式建立物件

重要性:5

想像一下,我們有一個任意物件 obj,是由建構函式建立的,我們不知道是哪一個,但我們想使用它來建立一個新的物件。

我們可以這樣做嗎?

let obj2 = new obj.constructor();

提供一個 obj 建構函式的範例,讓這樣的程式碼可以正確執行。以及一個讓它執行錯誤的範例。

如果我們確定 "constructor" 屬性有正確的值,我們可以使用這種方法。

例如,如果我們不變更預設的 "prototype",那麼這個程式碼一定會執行

function User(name) {
  this.name = name;
}

let user = new User('John');
let user2 = new user.constructor('Pete');

alert( user2.name ); // Pete (worked!)

它執行成功,因為 User.prototype.constructor == User

…但如果有人(姑且這麼說)覆寫了 User.prototype,卻忘記重新建立 constructor 來參照 User,那麼就會失敗。

例如

function User(name) {
  this.name = name;
}
User.prototype = {}; // (*)

let user = new User('John');
let user2 = new user.constructor('Pete');

alert( user2.name ); // undefined

為什麼 user2.nameundefined

以下是 new user.constructor('Pete') 的運作方式

  1. 首先,它在 user 中尋找 constructor。沒有。
  2. 接著,它遵循原型鏈。user 的原型是 User.prototype,它也沒有 constructor(因為我們「忘記」正確設定它!)。
  3. 在鏈中往上,User.prototype 是個純粹物件,它的原型是內建的 Object.prototype
  4. 最後,對於內建的 Object.prototype,有一個內建的 Object.prototype.constructor == Object。因此它會被使用。

最後,在最後,我們有 let user2 = new Object('Pete')

這可能不是我們想要的。我們想要建立 new User,而不是 new Object。那是遺失 constructor 的結果。

(如果你好奇的話,new Object(...) 呼叫會將其引數轉換為物件。那是一個理論上的東西,實際上沒有人會使用值呼叫 new Object,而且我們通常不會使用 new Object 來建立物件)。