js中的继承方式

js中继承的实现主要是通过原型链实现的,下面就一起来一下实现继承的方式吧(继承也是面试中常被问到的一个点哦)

原型链继承

  • 将父类的实例作为子类的原型实现继承

        function SuperType(){
          this.property = true;
        }
        SuperType.prototype.getSuperValue = function(){
          console.log(this.property);
        }
        function SubType(){
          this.subProperty = false;
        }
        SubType.prototype = new SuperType();
        SubType.prototype.getSubValue = function(){
          console.log(this.subProperty);
        }
        let sub = new SubType();
        console.log(sub);
    

    在这里插入图片描述

  • 特点:1)很纯粹的继承,实例是子类的实例,也是父类的实例

  • 缺点

    • 1)父类的实例属性变成了子类的原型属性,由于原型属性是共享的,一个实例修改了原型属性,会造成其它实例的原型也被修改,如下:
    • 2)子类型在实例化时不能给父类型的构造函数传参
        function SuperType(){
          this.colors = ['red', 'blue'];
        }
        function SubType(){
        }
        SubType.prototype = new SuperType();
        let instance1 = new SubType();
        instance1.colors.push('black');
        console.log(instance1.colors);  // ["red", "blue", "black"] 
        let instance2 = new SubType();
        console.log(instance2.colors);  // ["red", "blue", "black"]
    

盗用构造函数

  • 通过call在子类函数中实现父类函数的自执行

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

    在这里插入图片描述

  • 特点:

    • 1)继承了父类构造函数的属性,无法继承父类原型上的属性
    • 2)可以给父类构造函数进行传参
    • 3)可以继承多个构造函数的属性(call多个)
  • 缺点:

    • 1)必须在构造函数中定义方法,因此函数不能复用
    • 2)每个新实例都有父类构造函数的副本,臃肿
    • 3)子类不行访问父类原型上定义的方法

组合继承(结合原型链和盗用构造函数)

  • 使用原型链继承原型上的属性和方法

  • 通过盗用构造函数继承实例属性

        function SuperType(name){
          this.colors = ['red', 'blue'];
          this.name = name;
        }
        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);
        }
        let instance1 = new SubType('Zhang',2);
        instance1.colors.push('black');
        console.log(instance1);  // ["red", "blue", "black"] 
        let instance2 = new SubType('Li', 3);
        console.log(instance2);  // ["red", "blue"]
    

    在这里插入图片描述

  • 特点:组合继承弥补了原型链和盗用构造函数的不足,是js中使用最多的继承模式

  • 缺点:调用了两次父类构造函数(耗内存)

原型式继承

  • 借助原型,基于已有的对象创建并返回新的对象。本质上,object函数是对穿传入的对象执行了一次浅复制

  • ECMAScript 5通过增加Object.create方法将原型式继承的概念规范化了

        function object (o){
          function Fn(){}
          Fn.prototype = o;
          return new Fn();
        }
        let person = {
          name: 'Nicholes',
          friends: ['Court', 'Van']
        }
        let anotherPerson = object(person);
        anotherPerson.name = 'Greg';
        anotherPerson.friends.push('Rob');
    
        let yetAnotherPerson = object(person);
        yetAnotherPerson.name = 'Linda';
        yetAnotherPerson.friends.push('Barbie');
        console.log(anotherPerson, yetAnotherPerson);
    

    在这里插入图片描述

  • 特点: 类似于将一个对象浅复制,适用于不需要单独创建构造函数,但仍需要在对象间共享信息的场合

  • 缺点:属性中包含的引用值始终会在相关对象间共享,跟使用原型模式是一样的

寄生式继承

  • 创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,然后返回这个对象
    function object (o){
      function Fn(){}
      Fn.prototype = o;
      return new Fn();
    }
    function createAnother(original){
      let clone =object(original);  // 通过Object.create创建一个新对象
      clone.sayHi = function(){   // 以某种方式增强这个对象
        console.log('hi');
      }
      return clone;
    }
    let person = {
      name: 'Nicholes',
      friends: ['Court', 'Van']
    }
    let anotherPerson = createAnother(person);
    console.log(anotherPerson);
    anotherPerson.sayHi();

在这里插入图片描述

  • object() 函数不是寄生式继承所必需的,任何返回新对象的函数都可以在这里使用
  • 缺点:通过寄生式继承给对象添加函数会导致函数难以重用,与构造函数模式类似。

寄生式组合继承

  • 即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法;
  • 这里只调用了一次 SuperType 构造函数,避免了 SubType.prototype 上不必要也用不到的属性,因此可以说这个例子的效率更高。寄生式组合继承可以算是引用类型继承的最佳模式;
    function object (o){
      function Fn(){}
      Fn.prototype = o;
      return new Fn();
    }
    function inheritPrototype(subType, superType) {
      let prototype = object(superType.prototype); // 创建对象
      prototype.constructor = subType; // 增强对象
      subType.prototype = prototype; // 赋值对象
    }
    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;
    }
    inheritPrototype(SubType, SuperType);
    SubType.prototype.sayAge = function() {
      console.log(this.age);
    };
    let sub = new SubType('Anna', 18);
    console.log(sub);

在这里插入图片描述

class实现继承

  • Class通过 extends 关键字实现继承
  • super 在这里作为函数调用,表示父类的构造函数,用来新建父类的this对象
    class SuperType{
      constructor(name){
        this.name = name;
        this.colors = ["red", "blue", "green"];
      }
      sayName(){
        console.log(this.name);
      }
    }
    class SubType extends SuperType{
      constructor(name, age) {
        super(name);
        this.age = age;
      }
      sayAge(){
        console.log(this.age);
      }
    }
    let sub = new SubType('Anna', 18);
    console.log(sub);

在这里插入图片描述

文章参考:
JS中原型式和寄生式继承的详解(代码示例)
js 总结ES6中Class以及继承
JavaScript高级程序设计(第4版)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值