請記住,可以使用建構函式建立新物件,例如 new F()。
如果 F.prototype 是物件,則 new 營運子會使用它為新物件設定 [[Prototype]]。
JavaScript 從一開始就有原型繼承。它是該語言的核心功能之一。
但在過去,沒有辦法直接存取它。唯一可靠的方法是建構函式的 "prototype" 屬性,本章節會說明。因此,許多腳本仍然使用它。
請注意,這裡的 F.prototype 表示 F 上名為 "prototype" 的一般屬性。它聽起來與「原型」一詞類似,但這裡我們真正指的是具有此名稱的一般屬性。
以下是範例
let animal = {
eats: true
};
function Rabbit(name) {
this.name = name;
}
Rabbit.prototype = animal;
let rabbit = new Rabbit("White Rabbit"); // rabbit.__proto__ == animal
alert( rabbit.eats ); // true
設定 Rabbit.prototype = animal 實際上表示:「當建立 new Rabbit 時,將其 [[Prototype]] 指定為 animal」。
以下是結果
在圖片中,"prototype" 是水平箭頭,表示一般屬性,而 [[Prototype]] 是垂直箭頭,表示 rabbit 從 animal 繼承。
F.prototype 僅在 new F 時使用F.prototype 屬性僅在呼叫 new F 時使用,它會指定新物件的 [[Prototype]]。
如果在建立後,F.prototype 屬性變更(F.prototype = <另一個物件>),則由 new F 建立的新物件將具有另一個物件作為 [[Prototype]],但現有物件會保留舊物件。
預設的 F.prototype、建構函式屬性
每個函式都有 "prototype" 屬性,即使我們沒有提供它。
預設的 "prototype" 是僅有一個屬性的物件,該屬性為 constructor,指向函式本身。
如下所示
function Rabbit() {}
/* default prototype
Rabbit.prototype = { constructor: Rabbit };
*/
我們可以檢查它
function Rabbit() {}
// by default:
// Rabbit.prototype = { constructor: Rabbit }
alert( Rabbit.prototype.constructor == Rabbit ); // true
當然,如果我們什麼都不做,則所有兔子都可以透過 [[Prototype]] 使用 constructor 屬性
function Rabbit() {}
// by default:
// Rabbit.prototype = { constructor: Rabbit }
let rabbit = new Rabbit(); // inherits from {constructor: Rabbit}
alert(rabbit.constructor == Rabbit); // true (from prototype)
我們可以使用 constructor 屬性來使用與現有物件相同的建構函式建立新物件。
如下所示
function Rabbit(name) {
this.name = name;
alert(name);
}
let rabbit = new Rabbit("White Rabbit");
let rabbit2 = new rabbit.constructor("Black Rabbit");
當我們有一個物件,不知道哪個建構函式用於建立它(例如,它來自第三方程式庫),並且我們需要建立另一個相同類型的物件時,這很方便。
但 "constructor" 最重要的事情可能是...
...JavaScript 本身並未確保正確的 "constructor" 值。
是的,它存在於函式的預設 "prototype" 中,但僅此而已。之後發生什麼事 - 完全取決於我們。
特別是,如果我們將預設原型整體替換,則其中將沒有 "constructor"。
例如
function Rabbit() {}
Rabbit.prototype = {
jumps: true
};
let rabbit = new Rabbit();
alert(rabbit.constructor === Rabbit); // false
因此,為了保留正確的 "constructor",我們可以選擇將屬性新增/移除到預設 "prototype",而不是將其整體覆寫
function Rabbit() {}
// Not overwrite Rabbit.prototype totally
// just add to it
Rabbit.prototype.jumps = true
// the default Rabbit.prototype.constructor is preserved
或者,手動重新建立 constructor 屬性
Rabbit.prototype = {
jumps: true,
constructor: Rabbit
};
// now constructor is also correct, because we added it
摘要
在本章中,我們簡要地描述了為通過建構函式建立的物件設定 [[Prototype]] 的方法。稍後我們將看到更多依賴它的進階程式設計模式。
一切都相當簡單,只需幾個註解就能讓事情清楚
F.prototype屬性(不要將它誤認為[[Prototype]])在呼叫new F()時設定新物件的[[Prototype]]。F.prototype的值應該是物件或null:其他值將無法運作。"prototype"屬性只有在設定在建構函式上,並使用new呼叫時才有這種特殊效果。
在一般物件上,prototype 沒有什麼特別之處
let user = {
name: "John",
prototype: "Bla-bla" // no magic at all
};
預設所有函式都有 F.prototype = { constructor: F },因此我們可以透過存取物件的 "constructor" 屬性來取得物件的建構函式。
留言
<code>標籤,若要插入多行程式碼,請將它們包覆在<pre>標籤中,若要插入 10 行以上的程式碼,請使用沙盒 (plnkr、jsbin、codepen…)