(這篇會延續Constructor Function的內容,來解釋 Prototype 和 Prototypal inheritance。)
(想看結論可以看粗體跟移到最下面。)
在 4. 關於 Constructor Function 解釋建構子函式的文章時,有提到把屬性(properties)和方法(methods)都丟進建構子,這種建立物件的方式會占用到大量的記憶體。
我們可以先看看這個例子:
function Person(name, age, country){
this.name = name,
this.age = age,
this.country = country,
this.sayHi = function(){
console.log(this.name + " says Hi.");
}
}
let Tina = new Person("Tina", 22, "Taiwanese");
let Winnie = new Person("Winnie", 108, "Japanese");
console.log(Tina.sayHi === Winnie.sayHi); // output: false
Tina.sayHi
和Winnie.sayHi
的比較結果是不相等,要怎麼解釋這個結果呢?
也就是說,即使他們定義的method一模一樣,也會被當成不同的物件 → 指向不同的記憶體位置
那麼, 假設今天要製造一百個物件,就會製造一百個sayHi()
→ 占用一百個記憶體位置
這時侯我們可以利用prototype:
function Person(name, age, height){
this.name = name,
this.age = age,
this.country = country
}
Person.prototype.sayHi = function() { // 在Person的prototype屬性定義sayHi()
console.log(this.name + " says Hi");
}
let Tina = new Person("Tina", 22, "Taiwanese");
let Winnie = new Person("Winnie", 108, "Japanese");
console.log(Tina.sayHi === Winnie.sayHi); // output: true
從這裡可以知道,Tina.sayHi
和Winnie.sayHi
兩個函式嚴格相等(指向同樣的記憶體位置),這樣就可以解決佔用記憶體的災難。
那接下來要來了解,為什麼加入prototype可以解決這個問題?
所以我們要來認識JS的繼承(inheritance)和原型鍊(Prototype chain):
Prototype
(原型),而prototype本身也是一個object(物件)。null
,或參考至其他物件。In JavaScript, objects have a special hidden property [[Prototype]] (as named in the specification), that is either null or references another object. That object is called “a prototype”:
在程式語言中,這個行為被稱作 「原型繼承」。 (← 全文重點
When we read a property from object, and it’s missing, JavaScript automatically takes it from the prototype. In programming, this is called “prototypal inheritance”.
從我們剛剛執行的例子,我們可以執行console.log(Tina);
來瞭解他們的階層關係:
Tina
本身是建構子Person
創造出來的實例(instance)。Person()
。Object()
。由此可知,他們的繼承(查找)機制是這樣子:
Tina ---> Person.prototype(紅色框) ---> Object.prototype(綠色框) ---> Null
(JS 使用 constructor function 來定義物件的屬性與方法,而產生出的新物件被稱為實例(Instance)。)
最後補充一下MDN的定義:
講到繼承,JavaScript 就只有一個建構子:物件。
每個物件都有一個連著其他原型(prototype)的私有屬性(private property)物件。 原型物件也有著自己的原型,於是原型物件就這樣鏈結,直到撞見 null 為止:null 在定義裡沒有原型、也是原型鏈(prototype chain)的最後一個鏈結。
引用自 繼承與原型鏈 - JavaScript | MDN
做個結論:
→ 每個JS裡的物件(object),都繼承(inheritance)自該物件的原型(Prototype),並保留其屬性和方法。
→ 使用建構子函式產生實例以後,這些被產生的物件之間的連結被稱為原型鍊(Prototype chain)。
→ 當我們需要讀取一個物件的屬性,卻找不到時,JS會自動從從該物件的prototype查找,也就是原型繼承(prototypal inheritance)。
參考資料:
【如內文有誤還請不吝指教>< 謝謝閱覽至此的各位:D】
-----正文結束-----