JavaScript 繼承機制


Posted by rockyooooooo on 2021-06-30

JavaScript 沒有像其他物件導向程式設計的語言一樣,有內建 class 的機制,就算是 ES6 的 class 也只是語法糖,不過我們還是可以設計出一個類似 class 機制的功能,而可以達成這個目標靠的就是 原型鏈(Prototype Chain)

new

在 Java,我們要在一個 class 建一個新的 Instance 時,可以這樣寫:

Person p1 = new Person();

這行程式碼會建立一個 Person 的 instance 叫做 p1,而 JavaScript 也有 new 這個關鍵字,而 JavaScript 並沒有 class,所以後面接的會是一個 constructor function(建構函式),就像是 Java 在 new 一個新的 instance 時,都會呼叫 class 的 constructor(建構子)。

舉例來說,有個叫做 Person 的建構函式,p1 是一個 Person 的 instance。

function Person(name) {
    this.name = name
}

var p1 = new Person('allen')
console.log(p1) // Person, { name: 'allen' }

這時建構函式裡面的 this 就是這個新的 instance p1

我們也可以在 Person 裡面加入一些方法,並再建立一個新的 instance,也會同時有 namesayHello 可以用。

function Person(name) {
    this.name = name
    this.sayHello = function() {
        console.log(this.name + ': hello~')
    }
}

var p1 = new Person('allen')
var p2 = new Person('kaneshiro')
p1.sayHello() // allen: hello~
p2.sayHello() // kaneshiro: hello~

new 的小問題

我們現在的設計,沒有辦法共享這些屬性跟方法,這是什麼意思?p1p2 不是都有 namesayHello 嗎?

我們可以做一個測試就知道為什麼會這樣說了。

function Person(name) {
    this.name = name
    this.sayHello = function() {
        console.log(this.name + ': hello~')
    }
}

var p1 = new Person('allen')
var p2 = new Person('kaneshiro')
console.log(p1.sayHello === p2.sayHello) // false

也就是說,p1p2sayHello 是兩個不一樣的 function,頂多只是做一樣的事情而已,他們會各自占用一部分記憶體,如果有一百個甚至更多個 instance,他們各自的屬性跟方法就會各自占用一部份的空間,即使他們完全相同,造成很大的浪費。

Prototype

這時就用到了一個叫做 prototype 的屬性,只要把我們想要共享的屬性或方法,放到 prototype,所有 Person 的 instance 就可以共用這些屬性和方法,而其他不需要共享的就放在建構函式裡。

function Person(name) {
    this.name = name
}

Person.prototype.sayHello = function() {
    console.log(this.name + ': hello~')
}

var p1 = new Person('allen')
var p2 = new Person('kaneshiro')
p1.sayHello() // allen: hello~
p2.sayHello() // kaneshiro: hello~
console.log(p1.sayHello === p2.sayHello) // true

我們可以看到 p1p2 用的的確是同一個 sayHello,而且功能完全一樣。

總結

我們宣告了一個叫做 Person 的函式,這個函式可以稱為建構函式(constructor function),並把它當作 constructor 使用,我們還可以在 Person.prototype 加上你想要讓 instances 共享的屬性和方法。

再來用 var p1 = new Person('allen') 來建立一個新的 instance,而 p1 就可以有自己的 name,還有跟其他 instances 共用的 sayHello,這樣看起來就很像是 p1 繼承Personprototype

參考資料

該來理解 JavaScript 的原型鍊了
Javascript继承机制的设计思想
new operator


#javascript







Related Posts

34歲才開始自學寫程式會不會太晚?真的有心,永遠都不嫌晚。

34歲才開始自學寫程式會不會太晚?真的有心,永遠都不嫌晚。

讀書筆記-JavaScript技術手冊4: 物件進階語法

讀書筆記-JavaScript技術手冊4: 物件進階語法

component test 問題集4(React18 + TS + Jest + react-testing-library)

component test 問題集4(React18 + TS + Jest + react-testing-library)


Comments