ES5 繼承有許多中方式,我們這里只說普通常用的繼承方式
## 原型鏈賦值繼承
```js
function father(name){
this.name=name;
}
father.prototype.sayName=function(){
console.log(this.name);
}
function sub(age){
this.age=age;
}
sub.prototype=new father();
sub.prototype.sayAge=function(){
console.log(this.age);
}
```
上面就是典型的原型鏈賦值繼承,但是這個繼承是有缺點的,在繼承時需要 `new` 關鍵字進行處理。
## 構造函數繼承
```js
function father(name){
this.name=name;
this.age=22;
}
father.prototype.sayName=function(){
console.log(this.name);
}
function sub(){
father.apply(this,arguments)
}
var s=new sub("a")
> s
> sub {name: "a", age: 22}
age: 22
name: "a"
__proto__:
constructor: ? sub()
__proto__: Object
```
構造函數繼承最后在輸出中會發現并沒有 父級的方法 ,但是可以將數據傳到父級,與原型鏈繼承互補,所以衍生出組合繼承的方式
## 組合繼承
```js
function Father(name) {
this.name = name;
this.className = "Father"
}
Father.prototype.sayName = function () {
console.log(this.name)
}
function Sub(name) {
Father.apply(this, arguments)
}
//繼承原型
Sub.prototype = new Father();
var s=new Sub("張三",12);
```
不僅會繼承構造函數中的屬性,也會復制父類原型鏈中的屬性
但是在 `Sub.prototype = new Father();` 之后
Sub 的原型變成這樣的了
```js
> Sub.prototype
> {name: undefined, className: "person"}
```
也就是說Sub的原型中已經有了一個name屬性,而之后創建 s 時傳給構造的函數的name則是通過this重新定義了一個name屬性,相當于只是覆蓋掉了原型的name屬性(原型中的name依然還在),這樣很不優雅。
## 寄生組合繼承
```js
function Father(name) {
this.name = name;
this.className = "Father"
}
Father.prototype.sayName = function () {
console.log(this.name)
}
function Man(name,age) {
this.age=age;
Father.call(this, name)
}
// 注意此處
Man.prototype=Object.create(Father.prototype)
Man.prototype.sayAge=function(){
console.log(this.age)
}
```
這里用到了 `Object.creat(obj)` 方法,該方法會對傳入的obj對象進行淺拷貝。和上面組合繼承的主要區別就是:將父類的原型復制給了子類原型。這種做法很清晰:
1. 構造函數中繼承父類屬性/方法,并初始化父類。
2. 子類原型和父類原型建立聯系。
還有一個問題,就是constructor屬性,我們來看一下:
```js
> Father.prototype.constructor
< Father(name){
this.name=name;
this.className="Father"
}
> Sub.prototype.constructor
< Father(name){
this.name=name;
this.className="Father"
}
```
constructor是類的構造函數,我們發現,Father和Sub實例的constructor指向都是Father,當然,這并不會改變instanceof的結果,但是對于需要用到construcor的場景,就會有問題。所以一般我們會加上這么一句:
```js
Sub.prototype.constructor = Sub
```