美文网首页
面向对象从ES3到ES6的继承方法总结以及对比

面向对象从ES3到ES6的继承方法总结以及对比

作者: 叫兽儿 | 来源:发表于2018-10-11 16:21 被阅读0次

    继承是面向对象中一个非常重要的概念,javascript中可以实现继承,但不支持接口的继承,并且我们js中主要是依赖原型链实现继承的,下面说说从es3到es6中常见的几种继承方式:

    首先我们假设我们有两个类一个Television(电视)Computer(电脑)

    function  Television  () {
      this.name = '电视'
      this.telecontroller = '遥控器'
    }
    
    function  Computer  () {
      this.name = '电脑'
    }
    

    Television(电视)有个功能叫play(播放)Computer(电脑)有个compute(计算)的功能

    function  Television () {
      this.name = '电视'
      this.telecontroller = '遥控器'
    }
      
    Television.prototype.play =  '播放'
      
    function  Computer () {
      this.name = '电脑'
    }
      
    Computer.prototype.compute = '计算'
    

    然而我们知道Computer(电脑)也有play(播放)这个功能功能。那你会想到再给Computer(电脑)也添加一个play(播放)的功能不就好了,但是这样无形中浪费内存的资源,而且写起来也不比较繁琐,这不是我们想要的。这时候 继承 就出场了,而且实现继承的方式有很多种各有优缺点,接下来我们将每一种拿出来并对比一下他们的优缺点:

    一、原型链继承

    先上代码:

    function  Television  () {
      this.name =  '电视'
      this.telecontroller =  '遥控器'
    }
    
    Television.prototype.play =  '播放'
    
    function  Computer  () {
      this.name =  '电脑'
    }
    
    // 必须将这句写到上面否则下面的方法会被覆盖掉
    Computer.prototype =  new Television()
    
    // 因为new Television()实例没有constructor方法 所以我们要将constructor指向Computer
    Computer.prototype.constructor = Computer
    
    Computer.prototype.compute =  '计算'
    
    console.log(new Computer().name)  // 电脑
    console.log(new Computer().compute)  // 计算
    console.log(new Computer().play)  // 播放
    console.log(new Computer().telecontroller) // 遥控器
    console.log(Computer.prototype.name)  // 电视
    

    [注意]

    • Computer.prototype = new Television()必须写在子类定义原型方法(如现在的compute方法)之前,否则子类定义的原型方法会丢失(因为Computer.prototype指向堆内存地址变了)
    • 因为父类Television生成的对象是没有constructor属性,所以给他加上(为啥没有?我就不用再详细说了吧)

    [优点]

    • 实例是子类的实例,实际上也是父类的一个实例
    • 父类新增原型方法/原型属性,子类都能访问到

    [缺点]

    • 子类实例共享属性,造成实例间的属性会相互影响

    二、构造继承

    这个就比较简单啦,上代码:

    function  Television  () {
      this.name =  '电视'
      this.telecontroller =  '遥控器'
    }
    
    Television.prototype.play =  '播放'
    
    function  Computer  () {
      // 在这里直接调用父类的方法修改父类的this上下文
      Television.call(this)
      this.name =  '电脑'
    }
    
    Computer.prototype.compute =  '计算'
    
    console.log(new Computer().name)  // 电脑
    console.log(new Computer().compute)  // 计算
    console.log(new Computer().play)  // undefined
    console.log(new Computer().telecontroller) // 遥控器
    console.log(Computer.prototype.name)  // undefined
    

    [优点]

    • 简单明了,直接继承父类构造函数的属性及方法

    [缺点]

    • 无法继承父类原型链上的方法(new Computer().play //undefined

    三、组合继承

    原型链继承与构造继承相结合各取所长,看以下实现:

    function  Television  () {
      this.name =  '电视'
      this.telecontroller =  '遥控器'
    }
    
    Television.prototype.play =  '播放'
    
    function  Computer  () {
      Television.call(this)
      this.name =  '电脑'
    }
    
    Computer.prototype =  new Television()
    
    Computer.prototype.constructor = Computer
    
    Computer.prototype.compute =  '计算'
    
    console.log(new Computer().name)  // 电脑
    console.log(new Computer().compute)  // 计算
    console.log(new Computer().play)  // 播放
    console.log(new Computer().telecontroller) // 遥控器
    console.log(Computer.prototype.name)  // 电视
    

    [优点]

    • 子类既能继承父类构造函数中的属性和方法,又能继承父类原型链上的方法

    [缺点]

    • 子类会拥有父类的两份属性,只是子类属性将其覆盖了而已

    四、原型式继承

    原型式继承其实就是定义一个方法,传入Object,并不需要定义一个类,传入参数obj返回一个继承obj对象的新对象,实现如下:

    首先我们创建一个objectExtends方法

    var  obj = {
      name: '电视',
      telecontroller: '遥控器'
    }
    
    function  objectExtends(obj){
      function  F(){}
      F.prototype = obj
      return  new F()
    }
    
    console.log(new objectExtends(obj).name)  // 电视
    console.log(new objectExtends(obj).telecontroller)  // 遥控器
    

    [优点]

    • 简单易懂,直接通过对象生成一个继承该对象的新对象

    [缺点]

    • 不是类式继承,缺少类的概念

    五、寄生式继承

    这个名词很厉害,说白了就是原型式继承的加强版,同样传入Object,并不需要定义一个类,传入参数obj返回一个继承obj对象的新对象,然后在另一方法中以其他方式增强这个obj对象,返回最终的对象, 实现如下:

    首先我们创建一个objectExtendsobjectEnhance方法

    objectExtends方法作用依旧是实现原型式继承
    objectEnhance方法就是在objectExtends方法的基础上对新的obj对象扩展他的原型方法而已

    var  obj = {
      name: '电视',
      telecontroller: '遥控器'
    }
    
    function  objectExtends(oldObj){
      function  F(){}
      F.prototype = obj
      
      return  new F()
    }
    
    function  objectEnhance(obj){
      var  newObj = objectExtends(obj)
    
      newObj.property =  '扩展一个方法出来'
    
      return newObj
    }
    
    console.log(new objectEnhance(obj).name)  // 电视
    console.log(new objectEnhance(obj).telecontroller)  // 遥控器
    console.log(new objectEnhance(obj).property)  // 扩展一个方法出来
    

    [优点]

    • 相比原型式继承更加强悍,增强了原型式继承的能力

    [缺点]

    • 和原型式继一样,缺少类的概念

    六、寄生组合式继承

    看名字就知道寄生组合式继承就是结合了寄生式继承组合式继承,也是继承的终极解决方案

    function  Television  () {
      this.name =  '电视'
      this.telecontroller =  '遥控器'
    }
    
    Television.prototype.play =  '播放'
    
    function  Computer  () {
      Television.call(this)
      this.name =  '电脑'
    }
    
    Computer.prototype.compute =  '计算'
    
    function  inheritPrototype(Father,Son){
      var  newPrototype = Object.create(Father.prototype)
    
      newPrototype.constructor = Son
      Son.prototype = newPrototype
    }
    
    inheritPrototype(Television, Computer)
    
    console.log(new Computer().name)  // 电脑
    console.log(new Computer().play)  // 播放
    console.log(new Computer().telecontroller)  // 遥控器
    

    [优点]

    • 很完美

    [缺点]

    • 很繁琐

    七、ES6中的继承

    ES6的话就比较简单了,如果有不了解的可以去看看阮一峰的ECMAScript 6入门

    class  Television {
      constructor  () {
        this.name =  '电视'
        this.telecontroller =  '遥控器'
      }
    
      play  () {
        alert('播放')
      }
    }
    
    class  Computer  extends Television{
      constructor  () {
        super()
        this.name =  '电脑'
      }
    
      compute  () {
        alert('计算')
      }
    }
    
    console.log(new Computer().name)  // 电脑
    console.log(new Computer().play)  // ƒ play() { alert('播放') }
    console.log(new Computer().telecontroller)  // 遥控器
    

    [注意]

    • 如果你的子类重写了constructor方法,记得调用super,以确保父类构造逻辑运行

    [优点]

    • 和寄生组合式继承实现的效果一致

    最后献上两张关于ES5和ES6中继承的图片

    所以ES6和ES5的继承是一模一样的,只是多了classextends,ES6的子类和父类,子类原型和父类原型,通过__proto__连接

    End~

    相关文章

      网友评论

          本文标题:面向对象从ES3到ES6的继承方法总结以及对比

          本文链接:https://www.haomeiwen.com/subject/bsvbaftx.html