原文連接:https://ssshooter.com/2021-01...javascript
用了這麼多年的 JavaScript,對於原型鏈這東西自覺是理解了,可是平常工做中不多使用的「繼承」部分最近忽然想起來竟以爲有點陌生,因此在這裏稍微理一下思路。java
本文90%不能讓不懂原型鏈的人看懂原型鏈,可是可能能夠給懂一點原型鏈的人一點提示,不過若是本文讓你更混亂的話,請在評論區提出疑問 😂面試
只有函數有 prototype,對象沒有。ssh
// 函數 function A(){} A.prototype // 會輸出相似下面的東西 { constructor: A, __proto__: Object } // 對象 a = {} a.prototype // 輸出 undefined // 而若是你給一個對象賦予 prototype,效果不過是多了一個 prototype 屬性
__proto__
能夠當作一種「鏈接」,所到之處的屬性(property)均可以訪問。剛進坑的時候據說 __proto__
不是標準的屬性,可能會有不一樣的實現,但這麼多年過來了彷佛也就只用 __proto__
。函數
a = { c: 1 } a.hasOwnProperty('c') // 輸出 true
a 顯然沒有 hasOwnProperty 這個屬性,因而他會往 __proto__
找,在 Object.prototype 下找到 hasOwnProperty
並使用。this
通常,一個 __proto__
會被鏈接到一個 prototype,但你仍能夠直接定義 __proto__
prototype
a.__proto__ = { b: 'b' } a.b // 輸出 b
所謂的原型鏈就是由 __proto__
串成。code
例如一隻貓 let mona = new Feliscatus() __proto__ __proto__ __proto__ mona -----------> Cat.prototype -----------> Felis.prototype -----------> Felinae.prototype | | | | | 實例本身的屬性 | constructor Cat | constructor Felis | constructor Felinae | 其餘綁定在 prototype 的屬性 | 其餘綁定在 prototype 的屬性 | 其餘綁定在 prototype 的屬性 上一層找不到的東西就沿着 __proto__ 往下找,直到盡頭,找不到就是 undefined 了
__proto__
也能夠直接鏈接到一個對象(換句話就是,繼承一個對象的屬性):對象
const person = { isHuman: false, printIntroduction: function() { console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`) }, } let me1 = {} me1.__proto__ = person // 這樣 me1 就能使用 printIntroduction // 不過還有更方便一點的方法,使用 Object.create,這樣就不用本身鏈接 let me2 = Object.create(person)
在 new
一個對象時,實際上作了什麼,如何本身寫一個 new
(聽說面試會考,不過我沒遇到過):繼承
function Person(name) { this.name = name } Person.prototype.say = words => words // 這是一我的類 let person1 = new Person('Lilas') // 正經常使用 new 的結果是 // 1. 返回一個對象, // 2. 這個對象運行了構造函數, // 3. 這個對象可使用 Person 的 prototype 的屬性 // 知道了這三步,下面寫一個本身的 new function createInstance(klass, ...arg) { // 返回一個對象 let obj = {} // 以對象爲 this 運行構造函數 klass klass.call(obj, ...arg) // 爲了讓 obj 可使用 Person.prototype 使用 __proto__ 鏈接 obj.__proto__ = klass.prototype // 返回這個對象 return obj }
上面說過用 Object.create
繼承一個對象的屬性,這裏的繼承說的是「類」繼承。
JavaScript 在 ES6 以前,其實沒有類,所謂的繼承就是沿着原型鏈訪問父類(準確來講是 constructor)的變量和方法。
(順帶一提,想要了解 ES6 以後的類能夠看看 Class 繼承與 super,從這篇文章還能夠看出,ES6 的類不是單純的語法糖)
在 proto 部分說明了原型鏈的結構,下面講講實際上怎麼構造原型鏈。
// 上面已經有一個 Person 了,下面繼承 Person 寫一個 Boxer function Boxer(name, id) { // 在成爲格鬥者前他得是我的,因此先調用 Person 構造函數,至關於 super() Person.call(this, name) // 而後爲這個格鬥者加上本身的格鬥者 id this.id = id } // 添加 Boxer 本身的方法 Boxer.prototype.punch = () => 'punch!' // 接通到 Person.prototype Boxer.prototype.__proto__ = Person.prototype
不管接着還要繼承多少次,總之,記住 __proto__
串通了父子的 prototype
就行了。