• JS中的继承


    js中只有 实现继承, 没有接口继承.
     
    1.使用原型实现继承
     
      构造函数,对象实例 中都有指向 原型对象的指针
      但是构造函数实例和对象实例二者并没有直接联系(除了对象实例是用构造函数new出来这一点)
     
      试想,当类型A的原型对象 是其它类型(比如B类型)的 对象实例(b) 的时候
      那么A的prototype指向了b
          如果b本身的原型对象中的contructor指向了B,那么A继承自B
          如果b本身的原型对象是C类型的对象实例,那么A继承B,B继承C
          如果c本身的原型对象是 ...
          继续重复上面的步骤, 就形成了原型链
     
                                      TypeB                          TypeB.prototype
     
                         bridge(TypeA.prototype | instanceB)
      
      TypeA
     
      instanceA
     
     
      如上图:
        TypeA 以及 instanceA 都有指针指向 bridge(它既是TypeA的原型对象,又是TypeB的instance)
        既然 bridge是TypeB的对象实例,那么自然有指针指向TypeB的原型对象(TypeB.prototype)
        这时候instanceA 拥有了所有TypeB.prototype上的属性和方法.
        而 TypeB.prototype 上有constructor属性指向TypeB,instanceA也可以说是TypeB类型
     
      记住,无论原型链有多少环节,它总会有个末端,末端类型的原型对象 它是个Object类型的实例.
      所以会继承Object的所有属性和方法
     
    确定原型与实例之间的关系
      使用instanceof操作符 或者 Xxxx.prototype.isPrototypeOf(instance) 函数.
      只要在这个instance的原型链上出现过的构造函数,它们就会返回true,表示是这个类型.
     
    一定要先确定原型对象,然后再在原型上添加/覆盖 原型上的方法.
    而且,添加或覆盖 属性/方法 的时候,不要使用字面量的形式.那会切断和父级的链接.
     
    单独使用原型实现继承的缺点:
      ①.在创建对象的几种方式中,提到过原型模式.
        如果属性是引用类型的时候,会引发问题,所以这样的属性要放到构造函数中,而非原型对象上.
        但是,使用原型进行继承,会把别的类型的实例当做原型对象,
        那么别的实例中定义的属性,自然成为了本类型的原型属性,但这是个引用类型的属性,又回到了上面的问题
      ②.没有办法在不影响所有对象实例的情况下,给超类型的构造函数传递参数. // todo 如何理解?
    由于上述缺点,js中在实现继承的时候,不会单独的使用原型 来实现.
     
     
    2.借用构造函数
      原理很简单,就是在子构造函数中,调用超类的构造函数.
     
      function Super(name){ this.name = name; }
      function Child(){
        Super.call(this,"my name"); // 继承Super
        this.age = 30 ; // 定义实例属性
      }
      console.log(new Child().name);//display 'my name'
     
      这个方式对比单独使用原型的好处是,可以向超类型传递参数.
      坏处是,构造函数模式的通病,定义的方法无法复用.而且超类型原型上的属性和方法,无法被继承.
      所以,开发中也不会单独使用这种模式来实现继承.
     
    3.组合继承
      组合使用原型与借用构造函数来实现继承.
      原理很简单,超类实例属性用借用构造函数来继承;超类的原型属性和方法,用原型来继承.
      这种模式,是最经典的实现继承的方式.可以使用instanceof 以及 isPrototypeOf 来检查.
        
      function Super(name){
        this.name = name ;
      }
      Super.prototype.shareProp = "shareProp";
      Super.prototype.sayName = function(){
        console.log(this.name);
      }
     
      function Child(name ,age){
        Super.call(this,name);
        this.age = age ;
      }
      Child.prototype = new Super();
      Child.prototype.constructor = Child ;
      Child.prototype.sayAge = function(){
        console.log(this.age);
      };
     
      var c = new Child(); // 这时候实例c就拥有了 name,age,shareProp 属性,以及 sayName,sayAge 方法
     
      组合继承的缺点是
        会调用两次超类构造函数: new Super() 以及 Super.call(this,xxx);
        这算是个小缺点吧.
     
     
    4. 原型式继承
      在已有对象实例的情况下,借助它创建新的对象实例,而不用自定义新的类型.
      function createObject(origin){
        function F(){}
        F.prototype = origin ;
        return new F();
      }
     
      var origin = {
        name:"origin",
        friends:["a","b","c"]
      };
      var one = createObject(origin);
      one.friends.push("d");
      var another = createObject(origin);
      another.friends.push("e");
     
      console.log(origin.friends); //display a ~ e
     
      以上的函数,在ES5中已经标准化了, 即
        Object.create(origin,opts);
          origin : 参考对象.(该对象会被浅复制,然后赋给新对象)
          opts : 是指描述 加入到新对象的附加属性/方法;
                格式和 defineProperties()中定义特性的格式一样{name:{value:"xx"},age :{ value : 20 }}
     
    5. 寄生式继承
      在原型式继承上 进行了封装.
      不过耦合性太高,复用度不好.
      function CreateAdvObject(origin){
        //或者是 var clone = Object.create(origin); 只要可以生产对象就可以
        var clone = createObject(origin);
        clone.sayName = function(){}
        return clone;
      }
     
     
    6. 寄生组合式继承
      为了解决 组合继承中 调用了两次超类构造函数的问题.就是为了更高效一些.
      被称为 最完美的继承方式
      思路就是:
        不必为了指定子类型的类型,而去调用构造函数,只需要一个超类原型对象的副本而已.
        那么,这个副本,就由寄生式继承来创建吧.
        换句话说,将调用超类的构造函数做子类原型 ,转化为copy超类原型给子类用
     
        function InheritPrototype(targetType , superType){
          targetType.prototype = Obeject.create(superType.prototype) ;
          targetType.prototype.constructor = superType ;
        }
     
        function Super(){}
        function Child(){
          Super.call(this, arguments);
        }
     
        // 代替了原来的 两段代码
        // Child.prototype = new Super(); Child.prototype.constructor = Super;
        InheritPrototype(Child,Super);
     
        Child.prototype.sayChild = function(){
          console.log("sayChild");
        }
     
     
     
  • 相关阅读:
    TCP的三次握手与四次挥手
    HashMap源代码分析(JDK1.8)
    HashMap实现原理分析(JDK1.8前)
    codebook法分割前景目标
    平均场景法分割前景目标
    边缘梯度方向直方图的构建
    学习opencv 第六章 习题十三
    《学习OpenCV》 第四章 习题六
    《学习Opencv》第五章 习题6
    Opencv实现的简易绘图工具
  • 原文地址:https://www.cnblogs.com/lmxxlm-123/p/11131892.html
Copyright © 2020-2023  润新知