原型與繼承(2) - 原型鍊


Posted by TempuraEngineer on 2022-08-27

目錄


原型鍊 & 繼承

Javasctript和Java不同,它是prootype base的語言,而非class base

每個物件都有一個連結到其他物件的私屬性,而這個私屬性就是prototype

每個物件的prototype又有自己的prototype,這些prototype會一路指到null去。個一路往null指去的就是原型鍊

因為原型鍊,當你嘗試存取物件的某個屬性,不只會找物件本身,也會去找prototype,然後一路找到null去,所以太長的原型鍊、存取一個不存在的屬性會對效能造成衝擊

The lookup time for properties that are high up on the prototype chain can have a negative impact on the performance, and this may be significant in the code where performance is critical. Additionally, trying to access nonexistent properties will always traverse the full prototype chain.

不透過prototype的話你可能會這樣幫每個Person建立出來的實例加上方法

function Person(name, skill) {
    this.name = name;
    this.skill = skill;
}

function Politician(name, skill) {
    Person.call(this, name, skill);
}

function saySomethingRidiculous(content){
    return `${this.name}: ${content}`;
}

const clock = new Politician('時鐘', '報數');
const bald = new Politician('韓導', '膝蓋走路');

// 重複加上同個function顯然不太好
clock.saySomethingRidiculous = saySomethingRidiculous;
bald.saySomethingRidiculous = saySomethingRidiculous;

clock.saySomethingRidiculous('粗暴言論大可不必');
bald.saySomethingRidiculous('高雄發大財');

可以使用原型鍊的概念,將function加在建構函式的prototype,這樣就會自動傳給該建構函式建立的實例

prototype is the object that is used to build proto when you create an object with new

Every instance created from a constructor function will automatically have the constructor's prototype property as its [[Prototype]]

但需要注意,這也代表如果加saySomethingRidiculous在Person.prototype的話clock和bald是無法使用的

function Person(name, skill) {
    this.name = name;
    this.skill = skill;
}

function Politician(name, skill) {
    Person.call(this, name, skill);
}

Politician.prototype.saySomethingRidiculous = function(content){
    return `${this.name}: ${content}`;
}

const clock = new Politician('時鐘', '報數');
const bald = new Politician('韓導', '膝蓋走路');

clock.saySomethingRidiculous('粗暴言論大可不必');
bald.saySomethingRidiculous('高雄發大財');

要確認某個屬性是物件本身擁有,還是來自它的原型,可以使用hasOwnProperty()

// 如果透過clock.saySomethingRidiculous = saySomethingRidiculous;加屬性的話則會是true
Alex.hasOwnProperty('talkingShit'); // false代表來自prototype

Alex.hasOwnProperty('skill'); // true


prototype & __proto__

__proto__

實例的proto(在chrome看到會顯示[[prototype]])來自於建構函式的prototype

The Constructor.prototype property will become the [[Prototype]] of the constructor's instances

雖然目前瀏覽器仍支援這個屬性,但不推薦使用,因為它可能會從網頁標準被移除、目前只有被納入ES6標準

若可以的話用Object.getPrototypeOf()Object.setPrototypeOf()代替它

This feature is no longer recommended. Though some browsers might still support it, it may have already been removed from the relevant web standards, may be in the process of being dropped, or may only be kept for compatibility purposes.

The use of proto is controversial and discouraged. It was never originally included in the ECMAScript language spec, but modern browsers implemented it anyway. Only recently was the proto property standardized by the ECMAScript 2015 specification for compatibility with web browsers, so it will be supported into the future. It is deprecated in favor of Object.getPrototypeOf/Reflect.getPrototypeOf and Object.setPrototypeOf/Reflect.setPrototypeOf (though still, setting the [[Prototype]] of an object is a slow operation that should be avoided if performance is a concern).

prototype

兩者的關係

接下來透過建構函式和實例來看一下prototype與proto的關係

function Person(name, skill) {
    this.name = name;
    this.skill = skill;
}

function Politician(name, skill) {
    Person.call(this, name, skill);
}

const clock = new Politician('時鐘', '報數');

已知clock是由Politician new出來的,故Politician是它的constructor

clock.constructor; // ƒ Politician(name, skill) { Person.call(this, name, skill); }

// 故兩者會相等
clock.constructor.prototype === Politician.prototype; // true

再來__proto__會指向實例的constructor的prototype

clock.__proto__ === clock.constructor.prototype; // true
Object.getPrototypeOf(clock) === clock.constructor.prototype; // true

// 故兩者會相等
clock.__proto__ === Politician.prototype; // true
Object.getPrototypeOf(clock) === Politician.prototype; // true

建構函式的prototype.constructor預設會指向建構函式自身

Constructor.prototype by default has one own property: constructor, which references the constructor function itself

Politician.prototype.constructor === Politician;


參考資料

MDN - Object.prototype.proto
MDN - Inheritance and the prototype chain

函式 - 原型的起手式
js中proto和prototype的區別和關係
Javascripter 必須知道的繼承 prototype, [[prototype]], proto
proto VS. prototype in JavaScript


#prototype #原形鍊







Related Posts

JavaScript 五四三 Ep.04 Array.prototype.map()

JavaScript 五四三 Ep.04 Array.prototype.map()

隨堂練習:使用資料型別計算學生成績平均值

隨堂練習:使用資料型別計算學生成績平均值

[MTR04] W2 D1 JavaScript 基礎

[MTR04] W2 D1 JavaScript 基礎


Comments