《javascript高级程序设计》 继承实现方式

这篇原本应该是做为写JS 面向对象的前奏,只是做为《javascript高级程序设计》继承一章的笔记javascript

  • 原型链java

    • code 实现shell

      function SuperType() {
        this.colors = ['red','blue', 'green'];
      }
      function SubType() {
      }
      SubType.prototype = new SuperType();
      var instance1 = new SubType();
      instance1.colors.push("black");
      console.log(instance1.colors); // ['red','blue', 'green','black']
      
      var instance2 = new SubType();
      console.log(instance2.colors); // ['red','blue', 'green','black']
      
      var instance = new SuperType();
      console.log(instance.colors); // ['red','blue', 'green']
    • 使用原型链来实现继承,原型实际上会变成另外一个类型的实例,因而,原先的实例属性,会变成如今的原型属性了
    • 在建立子类的实例时,不能向父类的构造函数中传递参数
  • 借用构造函数segmentfault

    • code 实现继承函数

      function SuperType() {
        this.colors = ["red","blue","green"];
      }
      function SubType() {
        SuperType.call(this);
      }
      
      var instance1 = new SubType();
      instance1.colors.push("black");
      console.log(instance1.colors); // ["red", "blue", "green", "black"]
      
      var instance2 = new SubType();
      console.log(instance2.colors); // ["red", "blue", "green"]
      
      var instance = new SuperType();
      console.log(instance.colors); // ['red','blue', 'green']

    一样也能够实现参数的传递this

    function SuperType(name) {
      this.name = name;
    }
    function SubType(){
      SuperType.call(this, "jack");
      this.age = 29;
    }
    
    var instance = new SubType();
    console.log(instance.name); // jack
    console.log(instance.age); // 29
    • 若是仅仅是借用构造函数,那么将没法避免构造函数模式存在的问题--方法都在构造函数中定义,所以,函数复用也就无从谈起了。并且,在超类型的原型中定义的方法,对子类而言也是不可见的,结果全部类型都只能使用构造函数模式。
  • 组合继承prototype

    • 将原型链和借用构造函数的技术组合到一块,从而发回两者之长的一种继承模式。其背后的思路是使用原型链实现对原型属性和方法的继承,而经过借用构造函数来实现对实例属性的继承。这样,即经过在原型上定义方法实现了函数复用,又可以保证每一个实例都有它本身的属性。
    • code 实现设计

      function SuperType(name) {
        this.name = name;
        this.colors = ['red','blue','green'];
      }
      SuperType.prototype.sayName = function() {
        console.log(this.name);
      };
      function SubType(name, age) {
        SuperType.call(this, name);
        this.age = age;
      };
      
      SubType.prototype = new SuperType();
      SubType.prototype.sayAge = function(){
        console.log(this.age);
      };
      
      var instance1 = new SubType("jack", 29);
      instance1.colors.push("black");
      console.log(instance1.colors); //["red", "blue", "green", "black"]
      instance1.sayName(); // jack
      instance1.sayAge(); // 29
      
      var instance2 = new SubType("allen", 23);
      console.log(instance2.colors); // ["red", "blue", "green"]
      instance2.sayName(); //allen
      instance2.sayAge(); // 23
    • instanceOfisPrototypeOf 也可以用于识别基于组合继承建立的对象
  • 原型式继承code

    • 没有严格意义上的构造函数,经过借助原型,能够基于已有的对象建立新对象,同时还没必要所以建立自定义类型对象

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

    object() 函数内部,先建立了一个临时性的构造函数,而后将传入的对象做为这个构造函数的原型,最后返回这个临时类型的一个新实例。从本质上将,object() 对传入其中的对象执行了一次浅复制

    function object(o) {
        function F() {};
        F.prototype = o;
        return new F();
    }
    
    var person = {
        name:'jack',
        friends:['allen','lucy','van']
    }
    
    var anotherPerson = object(person);
    anotherPerson.name = 'bob';
    anotherPerson.friends.push('steve');
    
    var yetAnotherPerson = object(person);
    yetAnotherPerson.name = 'linda';
    yetAnotherPerson.friends.push('shelly')
    
    console.log(person.friends); //["allen", "lucy", "van", "steve", "shelly"]

    这种原型式继承,要求你必须有一个对象能够做为另外一个对象的基础。若是有这么一个对象的话,能够把他传递给object() 函数,而后再根据具体需求对获得的对象加以修饰便可。

    ECMAScript5 经过Object.create() 方法规范花了原型式继承。这个方法接受两个参数:一个用做新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。在传入一个参数的状况下,Object,create()object() 函数方法的行为相同

    在没有必要建立构造函数,而只是想让一个对象与另外一个对象保持相似的状况下,原型式继承是彻底能够胜任的。不过,包含引用类型值的属性始终都会共享响应的值,就像使用原型模式同样

  • 寄生式继承

    • 寄生式继承是与原型式继承紧密相关的一种思路。寄生式继承的思路与寄生构造函数和工厂模式相似,即建立一个仅用于封装继承过程的函数,该函数在内部已某种方式来加强对象,最后再像真的是它作了全部工做同样返回对象。

      function createAnother(original){
        var clone = object(original); // 经过调用 object() 函数建立一个新对象
        clone.sayHi = function(){  // 以某种方式来加强对象
          alert("hi");
        };
        return clone; // 返回这个对象
      }
    • 在主要考虑对象而不是自定义类型和构造函数的状况下,寄生式继承也是一种有用的模式。前面示范继承模式时使用的object() 函数不是必需的;任何可以返回新对象的函数都使用与此模式。
  • 寄生组合式继承

    • 组合继承是JavaScript 最经常使用的继承模式;不过也有本身的不足。组合继承最大的问题就是不管什么状况下,都会调用两次父类的构造函数:一次是在建立子类原型的时候,另外一次是在子类构造函数内部。

    子类最终会包含父类对象的所有实例属性,但咱们不得不在调用子类构造函数时重写这些属性。

    function SuperType(name) {
        this.name = name;
        this.colors = ['red','blue','green'];
    }
    
    SuperType.prototype.sayName = function(){
        console.log(this.name);
    }
    
    function SubType(name, age) {
        SuperType.call(this, name); // 第二次调用 SuperType()
        this.age = age;
    }
    
    SubType.prototype = new SuperType(); // 第一次调用 SuperType()
    SubType.prototype.constructor = SubType;
    SubType.prototype.sayAge = function() {
        console.log(this.age);
    };

    第一次调用SuperType 构造函数时,SubType.prototype会获得两个属性:namecolors,他们都是SuperType 的实例属性,只不过如今位于SubType 的原型中。当调用SubType 构造函数时,又会调用一次SuperType 构造函数,这一次又在新对象上建立了实例属性namecolors。 因而,这两个属性就屏蔽了原型中的两个同名属性。

    所谓寄生组合式继承,即经过借用构造函数来继承属性,经过原型链的混成形式来继承方法。其背后的基本思路是:没必要为了指定子类的原型而调用父类的构造函数,咱们所须要的无非就是父类原型的一个副本而已。本质上,就是使用寄生式继承来继承父类型的原型,而后再将结果指定给子类的原型。寄生组合式继承的基本模式以下

    function inheritPrototype(subType, superType) {
      var prototype = object(superType.prototype);
      prototype.constructor = subType;
      subType.prototype = prototype;
    }

    第一步是建立父类原型的一个副本,第二步是为建立的副本添加constructor 属性,从而弥补因重写原型而失去的默认的constructor 属性。第三步是将新建立的对象(即副本)赋值给子类的原型。

    function SuperType(name) {
        this.name = name;
        this.colors = ['red','blue','green'];
    }
    
    SuperType.prototype.sayName = function(){
        console.log(this.name);
    }
    
    function SubType(name, age) {
        SuperType.call(this, name); // 第二次调用 SuperType()
        this.age = age;
    }
    
    inheritPrototype(SubType, SuperType)
    SubType.prototype.sayAge = function() {
        console.log(this.age);
    };

    这个例子的高效率体如今它只调用了一次SuperType 构造函数,而且所以避免了在SubType.prototype 上建立没必要要的、多余的属性。于此同时,原型链还能保持不变;所以,还可以正常使用instanceofisPrototypeOf() 。开发人员广泛认为寄生组合继承是引用类型最理想的继承范式。

优缺点

  • 原型链会修改父类的属性,在建立子类的实例时,不能向父类的构造函数中传递参数
  • 借用构造函数,则没有继承
  • 组合继承(原型继承+借用构造函数) 组合继承最大的问题就是不管什么状况下,都会调用两次父类的构造函数:一次是在建立子类原型的时候,另外一次是在子类构造函数内部。
  • 原型式继承,要求你必须有一个对象能够做为另外一个对象的基础,
    包含引用类型值的属性始终都会共享响应的值,就像使用原型模式同样
  • 寄生式继承
    在主要考虑对象而不是自定义类型和构造函数的状况下,寄生式继承也是一种有用的模式
  • 寄生组合式继承 (这是最成熟的方法,也是如今库实现的方法)
    第一步是建立父类原型的一个副本,第二步是为建立的副本添加constructor 属性,从而弥补因重写原型而失去的默认的constructor 属性。第三步是将新建立的对象(即副本)赋值给子类的原型。


JS面向对象系列

相关文章
相关标签/搜索