JS继承实现

103 阅读2分钟

1.原型继承

  • 子类的原型为父类的实例,这样通过原型链即可以找到父类的属性或方法
  • 缺点:由于所有的子类实例都公用的同一个原型对象,所以继承引用类型的数据也是同一个,即修改一个全部都修改,不推荐
function Father(){
    this.name = "Alex"
    this.colors = ["red", "blue"]
}

function Child(){
    this.name = "child"
}

Child.prototype = new Father() //子类的原型为父类的实例

let p1 = new Child()
let p2 = new Child()
p1.colors.push("yellow")
p2.colors //["red", "blue", "yellow"]由于共享的是同一个原型,所以p1修改了,p2也会收到干扰

2.构造函数继承

  • 在子类里面执行父类构造函数且重新绑定this为子类
  • 缺点:每个子类实例继承了父类的属性,但是没法共享到父类原型上的属性或方法-不推荐
function Father(){
    this.name = "Alex"
    this.colors = ["red", "blue"]
}

Father.prototype.sayHello = () => {}

function Child(){
    Father.call(this) //在子类链执行父类构造函数
    this.name = "child"
}

let p1 = new Child()
p2.sayHello //error,因为子类没有继承父类原型上的方法sayHello

3.混合继承

  • 通过原型继承父类的方法,通过构造函数继承父类的属性,避免共享属性
  • 缺点: 执行了两次父类构造函数多余的开销,第一次子类里面执行父类构造函数,第二次子类原型等于父类实例的时候
function Father(){
    this.name = "Alex"
    this.colors = ["red", "blue"]
}

Father.prototype.sayHello = () => {}

function Child(){
    Father.call(this) //第一次执行父类函数,共享属性
    this.name = "child"
}

Child.prototype = new Father() //第二次执行父类函数,共享原型上的方法

4.原型式继承

  • 通过Object.create()方法来实现新建
  • Object.getPrototype(obj)获取对象的原型对象
  • Object.getOwnPropertyDescriptors(obj)
  • 优点是快捷,缺点: create是浅拷贝,同样对引用类型实现共享干扰
function Father(){
    this.name = "Alex"
    this.colors = ["red", "blue"]
}

cosnt Child1 = Object.create(Father)
cosnt Child2 = Object.create(Father)
Child1.colors.push("yellow")
Child2.colors //["red", "blue", "yellow"]
//由于看拷贝共享的是同一个原型,所以Child1修改了,Child2也会收到干扰

5.寄生式继承

  • 先拷贝一个对象,然后在次对象上扩展,最终返回次对象,就像新对象寄生在父类一样
  • 优点是可以随意扩展子类,缺点是浅拷贝,依旧存在数据共享干扰的问题
function Clone(obj){
    cosnt obj2 = Object.create(obj) //浅拷贝一个对象
    obj2.sayBey = () => {} //给该对象添加新属性
    return obj2
}

6.寄生组合继承-推荐

  • 通过寄生只浅拷贝父类原型-继承父类原型上的方法或属性
  • 通过构造函数继承父类属性,避免共享干扰
function clone(father, child){ //创建一个helper函数用于寄生父类原型
    const proto = Object.getPrototype(father) //获取父类的原型对象
    child.prototype = Object.create(proto) //拷贝父类原型并且赋值给子类原型
    child.prototype.constructor = child
}

function Father(){
    this.name = "Alex"
    this.colors = ["red", "blue"]
}

Father.prototype.sayHello = () => {}

function Child(){
    Father.call(this) //第一次执行父类函数,共享属性
    this.name = "child"
}
clone(Father, Child) //寄生继承父类原型

Child.prototype.sayBey = () => {}

const p1 = new Child()

7.ES6,extends继承

  • 其实就是寄生组合继承的语法糖
  • super函数执行
Class Child extends Father {
    constructor(name){
        super(name) //也就是执行父类构造函数且传入参数
    }
}