# 构造函数继承

  • 缺点:只能继承构造器属性,不能继承原型链方法
function Father(name, age) {
    this.name = name
    this.age = age
}

Father.prototype.sayAge = function() {
    return `hi,${this.age}`
}

function Son(name, age, school) {
    Father.call(this, name, age)
    this.school = school
}

let father = new Father('jamF', 40)
let son = new Son('jam', 15, 'whu')

console.log(son)
son.sayAge()    // 报错

# 原型链继承

  • 简单容易实现
  • 如果要现在子类实例的原型对象方法,必须要在new后面操作
  • 创建子类实例时候不能向父类构造函数中传参数
  • 无法实现多继承
function Father(name, obj) {
    this.name = name
    this.obj = obj
}
Father.prototype.sayName = function() {
    return this.name
}

function Son(name, obj, school) {
    this.name = name
    this.obj = obj
    this.school = school
}

// 子类原型对象指向父类实例,因为父类可能也有父类,
// 用原型的话,无法访问到祖父类的原型对象
Son.prototype = new Father()
Son.prototype.constructor = Son

// 新增原型对象方法必须要在new操作后
Son.prototype.saySchool = function() {
    return this.school
}

# 组合继承

  • 使用原型链实现对原型方法的继承,使用构造函数实现对实例属性的继承
  • 缺点会调用两次超类型的构造函数
function Father(name, age) {
    this.name = name
    this.age = age
}
Father.prototype.cars = ['benz', 'bwm']
Father.prototype.sayCars = function() {
    return this.cars
}

function Son(name, age, school) {
    Father.call(this, ...arguments)
    this.school = school
}

// 创建原型链, 此时还是需要用Father类的原型对象
Son.prototype = new Father()

Son.prototype.constructor = Son
// 优化方案
// Son.prototype.__proto = Father.prototype
// => Son.prototype = Object.create(Father.prototype)

# ES6继承

  • ES5的继承都是在子类中创建自己的this指向,最后将方法添加到this中
  • ES6的继承是使用关键字先创建父类的实例对象this,最后在子类class中修改this
class Father {
    x = 1
    constructor(name, age) {
        this.name = name
        this.age = age
        this.x = 2
    }

    static weight = '200KG'

    sayHello(){
        return `hello,i am ${this.name}`
    }
    
    static getWeight(){
        return this.weight
    }
    
    getAge(){
        return this.age
    }   
}

Father.prototype.sayName = function(){
    return this.name
}

class Son extends Father {
    
    constructor(name, age, school) {
        super(name, age);
        this.school = school
    }

    static weight = '50KG'

    normalMethodTest() {
        // 这里的super对象指向父类原型对象
        // super.y = Father.prototype.y
        
        // ES6规定,此处相当于 super.getAge.call(this)
        return super.getAge()
    } 
    static saticMethodTest(){
        // 静态方法内的super指向父类,且调用的静态方法内的this指向子类
        return super.getWeight()
    }    
}

# 实例继承

  • 不限制调用方式,简单易实现
  • 不能多次继承
function Father(name, age) {
    this.name = name
    this.age = age
}

Father.prototype.sayName = function() {
    return this.name
}

function Son(name, age, school) {
    let instance = new Father()
    instance.name = name
    instance.age = age
    instance.school = school
    return instance
}