在JavaScript中,原型的目的是為了「繼承」,達到物件之間的屬性可以共用。
原型是為了繼承,那要怎麼做可以讓物件可以繼承另一個物件呢?
可以用Object.create()
和建構子constructor
這兩個方法,這裡先寫Object.create()
,下一篇再提建構子的部分。
它會建立一個新的空物件,此空物件的原型是我們指定傳入的物件而實現繼承。此方法跟Object.assign()
不同,並不會複製物件的屬性喔!
動手做看看:
const obj = {
name:"Peter",
age:20
}
const newObj = Object.create(obj);
console.log(newObj); //{}
//查看空物件的原型
Object.getPrototypeOf(newObj);
Object.create(obj)
,創造出來的空物件原型繼承obj物件。{}
空物件,沒有任何物件屬性。Object.getPrototypeOf()
這個方法,得到{name:"Peter",age:20}
,表示obj是newObj的原型。在瀏覽器查看:
MDN:
When you try to access a property of an object: if the property can't be found in the object itself, the prototype is searched for the property. If the property still can't be found, then the prototype's prototype is searched, and so on until either the property is found, or the end of the chain is reached, in which case undefined is returned.
JavaScript的物件在存取屬性有預設行為,如在此物件找不到某屬性,就會透過[[Prototype]]
往原型上查找該,直到找到該屬性,如找不到則回傳undefined
。
舉個例子:
const animal = {
breath:function() {
console.log("呼吸!");
}
};
const dog = Object.create(animal);
dog.bark = function() {
console.log("汪!");
};
dog.bark(); //"汪!"
dog.breath(); //"呼吸!"
const dog = Object.create(animal)
使用animal作為原型建立dog物件。[[Prototype]]
指向animal。dog.bark
,呼叫 dog.bark()
時,印出 "汪!"
。dog.breath()
,JavaScript在dog物件中找不到breath方法,就沿著 [[Prototype]]
找到 animal物件並執行了breath方法。我們可以把共用的變數、方法放在prototype中,這樣所生成的物件皆能共享prototype中的方法,比放在建構函式內更能減少記憶體空間。
prototype
& __proto__
& [[Prototype]]
這幾個名詞容易搞混,整理了一下他們各自的說明~
prototype
:MDN這樣說:
In JavaScript, all functions have a property named prototype.
所有的函式都有prototype屬性。
prototype它是一個物件。
例如:建立一個sum函式,並用console.dir
查看內容,就能看到prototype屬性,而這個prototype展開可以發現有constructor
屬性,它指回sum函式。
當透過呼叫建構函式建立出的物件,此物件的原型__proto__
,被設定為建構函式的prototype
屬性。
範例:
function Person(name) {
this.name = name;
}
const personA = new Person("Peter");
console.log(personA.__proto__ === Person.prototype); // true
__proto__
:MDN這樣說:
The property of an object that points to its prototype is not called prototype. Its name is not standard, but in practice all browsers use
__proto__
.The standard way to access an object's prototype is the Object.getPrototypeOf() method.
物件指向其原型的屬性並不叫做prototype,所有瀏覽器都使用__proto__
,這個屬性名稱並非標準,標準存取物件原型的方法是Object.getPrototypeOf()
。
官方不建議直接使用
__proto__
,要存取物件原型,推薦使用Object.getPrototypeOf
。
__proto__
讓我們直接存取、修改物件的 [[Prototype]]
,可以把__proto__
看作 [[Prototype]]
的窗口。
[[Prototype]]
:是一個內部屬性,指向物件的原型,但無法直接存取操作它。
在瀏覽器顯示是灰色的。
以上分享~謝謝!
MDN - Object prototypes
Huli - 該來理解 JavaScript 的原型鍊了
JS 原力覺醒 Day21 - 原型
重新認識 JavaScript: Day 25 原型與繼承