昨天Prototype
世界的例子中,小白這種打電話讓別人再去打電話找的方式,其實就是一種Prototype Chain
的概念。
畫一張示意圖會比較清楚一些,用一個空的陣列來做舉例。
首先,陣列也是一種物件,空陣列代表裡面什麼都沒有,不過不代表不能從空陣列去獲取東西。
當我要從物件裡面找一個不存在的屬性,JavaScript就會直接從它的原型物件去找,要是它的原型物件沒有,就會再往上找它的原型物件,直到最上面,都沒有那就是找不到。
而這個最上面的原型物件就稱作叫Object.prototype
。
真的就最上面了,再往上找就是null
。
而這一個由下往最上尋找的過程,一層一層相依尋找,就是原型鏈。
這個可以拿來創造出一個擁有原型物件的新空物件,裡面的參數就帶要被繼承的原型物件,比如說:
const food = {
eat: true,
};
const apple = Object.create(food);
這個新被創造出來的物件其實原型物件就會自動綁定是food了,所以現在的apple也可以去看eat的這個屬性。
console.log(apple.eat); //true
除此之外,Object.create
還有一個很厲害的地方,它可以藉由放第二個參數,直接為新的物件增加額外的屬性。
const food = {
eat: true,
};
const apple = Object.create(food, {
red: {
value: true,
},
});
console.log(apple.red);//true
昨天只講到如何設定原型,其實還可以獲取原型,那就是使用Object.getPrototypeOf()
,這個語法會回傳物件中的原型物件。
用上面的例子來舉例:
const food = {
eat: true,
};
const apple = Object.create(food);
console.log(Object.getPrototypeOf(apple) === food);//true
apple的原型物件就是food,所以答案是true,證明沒想錯。
__proto__
其實也能做到相同的事情,不過使用__proto__
來進行設定或是獲取都是件不太好的事情(詳情請看昨天),所以請記得,現在主流的設定跟獲取方式:
但是__proto__
真的就一無可取之處嗎?那倒也不是,有一個用法的情境是不會被反對的。
__proto__
當作屬性時
圖片來源: MDN
看起來MDN裡面比較偏向說,不要使用. __proto__
的方式,但把__proto__
當作屬性時算是一個還蠻OK的方式。
也有查到其他地方也有這種說法:
The only usage of proto, that’s not frowned upon, is as a property when creating a new object: { proto: ... }.
說法出處:https://javascript.info/prototype-methods
讓我們來看看這方法是怎麼實作的吧。
創建一個新物件時,可以把__proto__
當作是屬性,然後它的value直接設定成所想要的原型物件。
有一個重點是,__proto__
的值必須是物件或是null,比如說值是字串就無法,其實蠻合理的,因為字串不能變成一個原型。
const food = {
eat: true,
};
const apple = {
color: "red",
__proto__: food,
};
const coconut = {
hardness: true,
__proto__: apple,
// 怕大家不知道所以講一下,coconut是椰子
};
在這邊有三個新創的物件,我利用__proto__
當屬性設定的方式,讓這三個物件形成一個原型鏈,藉由把apple的__proto__
設定成food,再把coconut的__proto__
屬性設定成apple,這樣一來,理論上應該可以在coconut使用到food的屬性,我們來測試看看。
console.log(coconut.eat); //true
看來結果沒有錯,確實已經藉由__proto__
當屬性的方式,把這三個物件串個原型鏈。
現在已經提到了Object.setPrototypeOf
以及obj.__proto__
都可以直接的去更改原型物件,影響整體的Prototype Chain
,但這是一件好的事情嗎?
關於這點去研究後,發現有些文章會說這個行為其實不是一件很好的事情,如下:
圖片來源:https://javascript.info/prototype-methods
大意就是,如果你今天覺得,速度很重要,就不要去修改已經存在的原型了,昨天有提到說,物件只能指定一種原型物件,要是去修改它,就會去覆蓋掉原本的原型物件,而這種行為,照那篇文章說,會去破壞掉object property access operations
的內部優化,簡單說就會會讓javascript
的執行速度變得很慢。
除非修改的重要程度比運行的速度還要重要,不然通常在創建物件時,就只會設置那麼一次,就不會再修改了,確實設計上是想改就改,但是除非有很確定自己在做什麼,不然我的理解是避免去做這件事情。
可能其它程式語言並不是如此,但在javascript
中就是透過Prototype Chain
來把上下關係給連接起來,藉此來達到繼承的方式,推薦大家可以去看huli的 該來理解 JavaScript 的原型鍊了,裡面講的很清楚好懂,那麼今天就是這些,我們明天見!
[1] Object.getPrototypeOf()
[2] Native prototypes