# JavaScript 繼承機制 ## Class JavaScript 沒有像其他物件導向程式設計的語言一樣,有內建 class 的機制,就算是 ES6 的 class 也只是語法糖,不過我們還是可以設計出一個類似 class 機制的功能,而可以達成這個目標靠的就是 [原型鏈(Prototype Chain)](https://hackmd.io/@allenliao/SkmnwKd3O)。 ### 讓你媽媽 new 一下 在 Java,我們要在一個 class 建一個新的 Instance 時,可以這樣寫: ```java Person p1 = new Person(); ``` 這行程式碼會建立一個 `Person` 的 instance 叫做 `p1`,而 JavaScript 也有 `new` 這個關鍵字,而 JavaScript 並沒有 class,所以後面接的會是一個 constructor function(建構函式),就像是 Java 在 `new` 一個新的 instance 時,都會呼叫 class 的 constructor(建構子)。 舉例來說,有個叫做 `Person` 的建構函式,`p1` 是一個 `Person` 的 instance。 ```javascript function Person(name) { this.name = name } var p1 = new Person('allen') console.log(p1) // Person, { name: 'allen' } ``` 這時建構函式裡面的 `this` 就是這個新的 instance `p1`。 我們也可以在 `Person` 裡面加入一些方法,並再建立一個新的 instance,也會同時有 `name` 跟 `sayHello` 可以用。 ```javascript 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 的小問題 我們現在的設計,沒有辦法共享這些屬性跟方法,這是什麼意思?`p1` 跟 `p2` 不是都有 `name` 跟 `sayHello` 嗎? 我們可以做一個測試就知道為什麼會這樣說了。 ```javascript 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 ``` 也就是說,`p1` 跟 `p2` 的 `sayHello` 是兩個不一樣的 function,頂多只是做一樣的事情而已,他們會各自占用一部分記憶體,如果有一百個甚至更多個 instance,他們各自的屬性跟方法就會各自占用一部份的空間,即使他們完全相同,造成很大的浪費。 ### Prototype 這時就用到了一個叫做 `prototype` 的屬性,只要把我們想要共享的屬性或方法,放到 `prototype`,所有 `Person` 的 instance 就可以共用這些屬性和方法,而其他不需要共享的就放在建構函式裡。 ```javascript 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 ``` 我們可以看到 `p1` 跟 `p2` 用的的確是同一個 `sayHello`,而且功能完全一樣。 ## 總結 我們宣告了一個叫做 `Person` 的函式,這個函式可以稱為建構函式(constructor function),並把它當作 constructor 使用,我們還可以在 `Person.prototype` 加上你想要讓 instances 共享的屬性和方法。 再來用 `var p1 = new Person('allen')` 來建立一個新的 instance,而 `p1` 就可以有自己的 `name`,還有跟其他 instances 共用的 `sayHello`,這樣看起來就很像是 `p1` **繼承**了 `Person` 的 `prototype`。 ## 參考資料 [該來理解 JavaScript 的原型鍊了](https://blog.huli.tw/2017/08/27/the-javascripts-prototype-chain/) [Javascript继承机制的设计思想](https://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html) [new operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new) ###### tags: `Lidemy-MTR05`, `Week16`