美文网首页
第6章 面向对象的程序设计 (下)

第6章 面向对象的程序设计 (下)

作者: Shiki_思清 | 来源:发表于2020-04-28 01:17 被阅读0次

    3. 继承

    1.原型链

    原文:利用原型让一个引用类型继承另一个引用类型的属性和方法。
    根据上篇末尾的总结的构造函数与原型与实例之间的关系,如果A实例不是指向A实例自己的prototype,而是指向了B实例的prototype,也就是B.prototype = A实例,这时候B再创建实例,就会获得A的prototype对象的属性及方法,还有A构造函数本身的属性及方法。

    同时,所有函数的默认原型,都是Object的实例, 因此 默认原型都会最终指向Object.prototype

    SubType.prototype = new SuperType()  // A的实例指向了B的prototype
    

    问题: 1.引用类型值的原型属性会被所有实例共享。2. 创建父类型实例时同时传参,子类型创建的所有实例都会共享父类型的参数

    2. 借用构造函数

    利用apply() call()这种超类型构造函数
    在子类型构造函数的内部调用超类型构造函数

    function SuperType() {
      this.colors = ['red', 'green']
    }
    function SubType() {
      SuperType.call(this)
    }
    var instance1 = new SubType()
    instance1.colors.push('black')  // ['red', 'green', 'black']
    var instance2 = new SubType()
    instance2.colors  // ['red', 'green']
    
    • 这样每个实例都会有自己的colors副本

    问题:方法都在各自的构造函数中定义,无法复用

    3.组合继承

    将原型链和借用构造函数混合使用,原型链实现对原型属性和方法的继承,借用构造函数实现对实例属性的继承

     function SuperType(name) {
      this.name = name
      this.colors = ['red', 'green']
    }
    SuperType.prototype.sayName = function() {}
    function SubType(name) {
      SuperType.call(this, name)
    }
    // 继承方法‘
    SubType.prototype = new SuperType()  // SubType.prototype.constructor是SuperType
    SubType.prototype.constructor = SubType   // 手动指回SubType
    var instance = new SupType()
    // 此时 colors是特有的,而sayName() 是共有的
    

    原型式继承

    原始方式是

    function object(o) {
      function F(){}
      F.prototype = o
      return new F()
    }
    

    使用ES5中的Object.create() , 接收两个参数,一是一个模板对象,二是get、set方法

    var person = {
      name: 'Nicol';
      colors: ['Shely', 'Bob']
    }
    var person1 = Object.create(person)
    person1.name = 'Dada' 
    person1.colors.push('Hey')   // ['Shely', 'Bob', 'Hey']
    var person2 = Object.create(person)
    person2.colors  // ['Shely', 'Bob', 'Hey']
    person2.name //  'Nicol'
    

    问题:同样的使用原型模式都是一样的问题,就是共享引用类型值

    寄生式继承

    即创建一个仅用于封装 继承过程的函数,在内部以寄生的方式来增强对象,最后像是真的是它做了所有工作一样返回对象。

    function createAnother(original) {
      var clone = object(original)  // 通过调用一个返回新对象的函数,创建一个新对象。例如Object.create()
      clone.sayHi = function() {  // 以某种方式在内部像寄生一样增强这个对象
        alert('Hi')
      }
      return clone;
    }
    

    寄生组合式继承

    可以看上面组合继承,调用两次SuperType()的构造函数

     function SuperType(name) {
      this.name = name
      this.colors = ['red', 'green']
    }
    SuperType.prototype.sayName = function() {}
    function SubType(name) {
      SuperType.call(this, name) // 第二次调用SubType构造函数时
    }
    // 继承方法‘
    // ---------------->
    SubType.prototype = new SuperType()  // 第一次调用SuperType构造函数时
    SubType.prototype.constructor = SubType 
    // <----------------
    var instance = new SupType()
    

    两次调用,就会创建两次 name和colors属性,第二次会覆盖第一次,
    实际第一次调用,为了共享原型链上的方法,没必要调用构造函数,
    所以可以使用,原型链的继承的混成模式

    function inheritPrototype(subType, superType) {
      var prototype = object(superType.prototype)
      prototype.constructor = subType
      subType.ptototype = prototype
    }
    // 再将上面---> <-----中的代码替换成下面
    inheritPrototype(SubType, SuperType);
    

    总结

    这么多莫名其妙的名称,什么原型式,借用构造函数,寄生式等等,真叫人头疼,不得不让我好好看看他们的区别:
    原型链 --------------------> 用prototype继承,缺点:所有属性共享
    原型式继承---------------> Object.create(obj)等返回一个对象,缺点:引用属性共享
    借用构造函数 -----------> apply() call(),内部独享了。缺点:方法不共享
    组合继承------------------> 原型链和借用构造函数两个一起来。 缺点:调用了两次父类构造函数
    寄生式继承 --------------> 在内部用各种方法增强一个临时对象,最后返回这个对象。伏笔
    寄生组合式继承---------> 用寄生式继承的思想创建一个混成模式,解决组合继承中调用两次父类构造函数的问题。堪称完美了。

    相关文章

      网友评论

          本文标题:第6章 面向对象的程序设计 (下)

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