iT邦幫忙

2024 iThome 鐵人賽

DAY 20
1

prototype 原型

在JavaScript中,原型的目的是為了「繼承」,達到物件之間的屬性可以共用。

設定物件原型

原型是為了繼承,那要怎麼做可以讓物件可以繼承另一個物件呢?

可以用Object.create()和建構子constructor這兩個方法,這裡先寫Object.create(),下一篇再提建構子的部分。

Object.create()

它會建立一個新的空物件,此空物件的原型是我們指定傳入的物件而實現繼承。此方法跟Object.assign()不同,並不會複製物件的屬性喔!

動手做看看:

const obj = {
    name:"Peter",
    age:20
}

const newObj = Object.create(obj);
console.log(newObj); //{}

//查看空物件的原型
Object.getPrototypeOf(newObj);
  1. 先建立一個obj物件,裡面有name和age兩個屬性。
  2. 使用物件方法Object.create(obj),創造出來的空物件原型繼承obj物件。
  3. 印出newObj確認,確實是一個{}空物件,沒有任何物件屬性。
  4. 要存取newObj物件的prototype,使用Object.getPrototypeOf()這個方法,得到{name:"Peter",age:20},表示obj是newObj的原型。

在瀏覽器查看:
Object.create

prototype chain 原型鍊

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(); //"呼吸!"
  1. const dog = Object.create(animal) 使用animal作為原型建立dog物件。
  2. dog的 [[Prototype]] 指向animal。
  3. 在dog物件新增bark方法dog.bark,呼叫 dog.bark() 時,印出 "汪!"
  4. 當呼叫 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函式。
函式的prototype

當透過呼叫建構函式建立出的物件,此物件的原型__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]]

是一個內部屬性,指向物件的原型,但無法直接存取操作它。

在瀏覽器顯示是灰色的。
[[Prototype]]

以上分享~謝謝!

參考資料

MDN - Object prototypes
Huli - 該來理解 JavaScript 的原型鍊了
JS 原力覺醒 Day21 - 原型
重新認識 JavaScript: Day 25 原型與繼承


上一篇
[Day 19] this - 下
下一篇
[Day 21] 建構函式 constructor function
系列文
JavaScript學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言