# 概述
本文主要記錄js中實(shí)現(xiàn)繼承的幾種方法的實(shí)現(xiàn),優(yōu)缺點(diǎn)分析
# 知識(shí)鋪墊
+ **構(gòu)造函數(shù),原型和實(shí)例的關(guān)系:**
+ 每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象--prototype
+ 每個(gè)原型對(duì)象都包含一個(gè)指向構(gòu)造函數(shù)的指針--constructor
+ 每個(gè)實(shí)例對(duì)象都有一個(gè)指向原型對(duì)象的指針
+ 構(gòu)造函數(shù)可以new實(shí)例對(duì)象
>**圖解三者關(guān)系**
![FvvO2t.png](https://s2.ax1x.com/2019/01/13/FvvO2t.png)
---
# 原型繼承
+ **核心思想:**
> 將父類的實(shí)例直接賦值給子類的原型對(duì)象prototype
+ **本質(zhì)**
>重寫了子類的原型對(duì)象邑退,原本存在父類的屬性和方法也存在于子類的prototype中了
+ **代碼演示**
```
//父類
function Person() {
? ? this.name = 'Tom'
? ? this.age = 18
}
//子類
function Student() {
? ? this.score = 100
}
//父類的實(shí)例賦值給子類的原型對(duì)象
Student.prototype = new Person()
Student.prototype.constructor = Student
let student1 = new Student();
console.log(student1.name,student1.age,student1.score)
console.dir(Student)
```
+ **打印結(jié)果:**
![FxpNZT.png](https://s2.ax1x.com/2019/01/13/FxpNZT.png)
+ **打印結(jié)果解析**
+ 首先,我們將Person的實(shí)例賦值給Student.prototype,這樣在Student.prototype中就存在了Person中的屬性和方法
+ 其次救斑,如果我們不添加黃色方框中的代碼换淆,那么Student.prototype中的constructor指向的就是Person
當(dāng)添加了黃色方框中的代碼后哗总,Student.prototype中的constructor又重新指向了Student
+ **原型繼承存在的問題**
+ 通過原型實(shí)現(xiàn)繼承時(shí)几颜,原型會(huì)變成另一個(gè)類型的實(shí)例,所以**要通過黃色方框繼承后將原型的構(gòu)造函數(shù)重新指向原來的構(gòu)造函數(shù)**
+ 使用原型繼承時(shí)讯屈,**不能向父類的構(gòu)造函數(shù)傳參**
---
# 借用構(gòu)造函數(shù)(解決傳參問題)
+ **核心思想**
> 使用call()方法改變this指向蛋哭,實(shí)現(xiàn)**屬性**繼承
+ **本質(zhì)**
> 在子類的構(gòu)造函數(shù)中調(diào)用父類構(gòu)造函數(shù)并使用call()使this指向子類實(shí)例
+ **代碼實(shí)現(xiàn)**
```
function Person(name,age) {
? ? this.name = name
? ? this.age = age
? ? this.play = function () {
? ? ? ? console.log(this.name + '玩游戲')
? ? }
}
Person.prototype.test = function () {
? ? console.log(this.name + '參加考試')
}
function Student(name,age,score) {
? ? Person.call(this,name,age)
? ? this.score = score
}
let student1 = new Student('Tom',18,100)
let student2 = new Student('Jerry',18,96)
console.dir(student1)
console.dir(student2)
student1.play()
student1.test()
```
+ **打印結(jié)果**
![Fxl9wF.png](https://s2.ax1x.com/2019/01/14/Fxl9wF.png)
+ **打印結(jié)果解析**
> + ***序號(hào)1***處,在子類的構(gòu)造函數(shù)中使用了call()方法涮母,繼承了父類的屬性和**定義在構(gòu)造函數(shù)中的成員方法(不能繼承定義在原型上的方法)**
> + ***序號(hào)2***處具壮,因?yàn)槭褂玫臉?gòu)造函數(shù)的形式,為了避免方法的重復(fù)定義哈蝇,所以將方法定義在原型上棺妓,但這樣不能繼承,要想繼承炮赦,就定義在構(gòu)造函數(shù)內(nèi)部
+ **存在的問題**
+ 借用構(gòu)造函數(shù)雖然解決了傳參問題怜跑,但是還是解決不了函數(shù)的重復(fù)定義問題
---
# 組合繼承
+ **核心思想**
> 組合就是原型繼承(繼承方法)+借用構(gòu)造函數(shù)(繼承屬性)的組合
+ **本質(zhì)**
> + 把父類的方法定義在原型上,通過原型繼承吠勘,讓子類原型中擁有父類的成員方法
> + 把屬性定義在構(gòu)造函數(shù)中性芬,子類通過call()方法繼承父類屬性
+ **代碼演示**
```
function Person(name,age) {
? ? this.name = name
? ? this.age = age
}
Person.prototype.play = function () {
? ? console.log(this.name + '在玩游戲')
}
function Student(name,age,score) {
? ? Person.call(this,name,age)
? ? this.score = score
}
Student.prototype = new Person()
Student.prototype.constructor = Student
let student1 = new Student('Tom',18,100)
console.log(student1)
student1.play()
let student2 = new Student('Jerry',10,60)
console.log(student2)
student2.play()
```
+ **打印結(jié)果**
![Fx3RJJ.png](https://s2.ax1x.com/2019/01/14/Fx3RJJ.png)
+ **打印結(jié)果解析**
> + ***序號(hào)1***處使用借助構(gòu)造函數(shù)的形式實(shí)現(xiàn)屬性繼承
> + ***序號(hào)2***處采用原型繼承的方式,繼承了定義在原型方法上的成員方法(**使用原型繼承后剧防,記得將子類的原型中的構(gòu)造函數(shù)指針重新指會(huì)子類的構(gòu)造函數(shù)**)