iT邦幫忙

2023 iThome 鐵人賽

DAY 22
0
自我挑戰組

一個月的後端學習之旅系列 第 22

【DAY22】繼承、原型鏈、Prototype Inheritance in Constructors

  • 分享至 

  • xImage
  •  

繼承 Inheritance

在JavaScript中,每個物件都有一個private attribute叫做__proto__

__proto__屬性存放的值是另一個物件

若物件A的__proto__屬性的值是設定成另一個物件B,則物件A就繼承了物件B的所有attributes以及methods

let phoebe = {
  name: "Phoebe",
  sayHi() {
    console.log("說你好");
  },
};

let darren = {
  __proto__: phoebe,
};

console.log(darren.name); // -> Phoebe
darren.sayHi(); // -> 說你好

每個constructor function都可以設定prototype屬性(prototype屬性本質上來說,就是一個empty object)

所有從constructor function製作出來的物件, 其__proto__屬性都是自動指向constructor function的prototype屬性

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.sayHi = function () {
    console.log(this.name + "說你好");
  };
}

// console.log(Person.prototype) // -> {} empty object

let phoebe = new Person("Phoebe", 23); // -> phoebe.__proto__ => Person.prototype
let darren = new Person("Darren", 25); // -> darren.__proto__ => Person.prototype

obj.proto 以及 A.prototype都是 reference data type,所以true代表兩者指向同個記憶體位置

console.log(phoebe.__proto__ == Person.prototype); // -> true

constructor function的prototype屬性繼承attributes and methods的原理,就叫做Prototype Inheritance

若從constructor function製作出的每個物件都有相似的methods,我們可以把methods全部移動到constructor function的prototype屬性內部,而不是在個別的物件中重複定義methods

設定一個function

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.sayHi = function () {
    console.log(this.name + "說你好");
  };
}

Person.prototype.hello = function () {
  console.log(this.name + "說你好");
};

phoebe.hello(); // -> phoebe說你好
console.log(phoebe.hello == darren.hello); // -> true

設定attributes

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.sayHi = function () {
    console.log(this.name + "說你好");
  };
}

Person.prototype.type = "人類";

console.log(phoebe.type); // -> 人類

使用constructor function來做物件的好處在於:

  1. 程式碼容易撰寫且維護,大量物件可以透過 constructor function 來製作

  2. 節省記憶體空間。兩個物件若有可以共用attritubes或methods,但分開製作,則會分別佔用記憶體內的不同位置。若使用constructor function 來製作,則兩個物件繼承來的attributes以及methods都是指向記憶體的相同位置

原型鏈 Prototype Chain

JS內建的資料類型都有繼承其他的Prototype

例如,[1, 2, 3]這個array繼承了Array Prototype,而Array Prototype又繼承自Object Prototype

這種Prototype不斷往上連結的結果就叫做Prototype Chain

JavaScript中的所有物件最後的 Prototype Chain 都會連到一個叫做 Object Prototype的地方,是 Prototype Chain 的終點

Prototype Inheritance in Constructors

一個 constructor function A 可以透過兩個設定來繼承另一個 constructor function B 的 prototype 物件:

  1. 在 constructor function A 的內部執行B.call(this, args1, …, argsN)。我們可以透過這段程式碼直接將 B 所設定的屬性套給 A 做使用
  2. 設定A.prototype = Object.create(B.prototype)。 Object.create()可以創建一個全新的物件

這樣一來,所有在 B.prototype 內部的 attributes 與 methods 都可以套用給 A.prototype

所有 A.prototype 所設定的額外的 attributes 與 methods 都需要寫在 A.prototype = Object.create(B.prototype)這行程式碼的下方

不能寫 A.prototype = B.prototype 是因為,constructor.prototype 是reference data type

// 如果寫
A.prototype = B.prototype;
A.prototype.add = function() {}
// 則A, B兩個prototype都指向記憶體的相同位置,且兩個prototype都有add()這個methods了
function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.sayHi = function () {
  console.log(this.name + "說你好");
};

function Student(name, age, major, grade) {
  Person.call(this, name, age);
  this.major = major;
  this.grade = grade;
}

Student.prototype = Object.create(Person.prototype);
Student.prototype.study = function () {
  console.log(this.name + "正在努力讀" + this.major);
};

let Phoebe = new Student("Phoebe Lee", 23, "Math", 3.5);
Phoebe.sayHi();// -> Phoebe Lee說你好
Phoebe.study();// -> Phoebe Lee正在努力讀Math

let Darren = new Person("Darren Lo", 25);
Darren.study(); // -> Uncaught TypeError: Darren.study is not a function

如果沒有寫在 Object.create 下面

Student.prototype.study = function () {
  console.log(this.name + "正在努力讀" + this.major);
};

Student.prototype = Object.create(Person.prototype);

Phoebe.study(); // -> Uncaught TypeError: Phoebe.study is not a function

下一篇文章學習進階的靜態與動態網頁、網頁開發工具。


上一篇
【DAY21】遞迴、費波那契數列
下一篇
【DAY23】 靜態與動態網頁、網頁開發工具
系列文
一個月的後端學習之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言