六种方式实现原生JS继承

463 阅读3分钟

本文用简洁的代码,六种方式实现原生JS继承,会让你看完之后,直呼好简单;理解继承首先需要理解原型、原型链this指向,原型、原型链可以参考我这篇文章:轻松理解JS 原型原型链

一:构造函数绑定

实现方式 :使用call或apply方法,将父对象的构造函数绑定在子对象上

缺点:

1: 只继承了父类构造函数的属性,继承不到父类原型对象上的属性

优点:

1: 解决了原型链继承缺点1、2、3。

    function Animal(weight) {
      this.species = '动物';
      this.weight = weight;
    }
    Animal.prototype.love = '肉'

    function Cat(name, color) {
      Animal.call(this, '18斤');
      this.name = name;
      this.color = color;
    }
    let cat = new Cat('大毛', '黄色');
    console.log(cat)
    // 打印结构
    // color: "黄色"
    // name: "大毛"
    // species: "动物"
    // weight: "18斤"
    // love: undefined  缺点: 继承不到父类原型对象上的属性

二:直接继承prototype

实现方式 :直接继承Animal.prototype。

缺点:

1: Cat.prototype和Animal.prototype现在指向了同一个对象,那么任何对Cat.prototype的修改,都会反映到Animal.prototype。

2: 只能继承到父类原型对象上的属性, 继承不到父类构造函数的属性,如species、weight

    function Animal(weight) {
      this.species = '动物';
      this.weight = weight;
    }
    Animal.prototype.love = '肉'

    function Cat(name, color) {
      this.name = name;
      this.color = color;
    }

    Cat.prototype = Animal.prototype;
    Cat.prototype.constructor = Cat;
    let cat = new Cat('大毛', '黄色');
    // 打印结构
    //     color: "黄色"
    //     name: "大毛"
    //     __proto__:
    //        love: "肉"
    Animal.prototype.love // 此时是’肉‘
    Cat.prototype.love = '喵粮'
    Animal.prototype.love // c此时是喵粮  Cat.prototype的修改,都会反映到Animal.prototype

三:原型链继承

实现方式:如果"猫"的prototype对象,指向一个Animal的实例,那么所有"猫"的实例,就能继承Animal了。

缺点:

1:每次需要重新创建Animal实例,费内存

2: 新实例无法向父类构造函数传参。

3: 所有新实例都会共享父类实例的属性 此处共享species属性

    function Animal(weight) {
      this.species = '动物';
      this.weight = weight;
    }
    Animal.prototype.love = '肉'

    function Cat(name, color) {
      this.name = name;
      this.color = color;
    }

    Cat.prototype = new Animal('19斤'); // 新实例无法向父类构造函数传参。此处不是传了’19‘斤吗 :因为在继承之前,就定义好的,不能new Cat()时传入
    // 此处修正继承链,因为 new Animal()生产的实例,constructor指向Animal,执行 Cat.prototype = new Animal();后,Cat.prototype原先的constructor被覆盖,constructor的指向来自new Animal()生产的实例
    Cat.prototype.constructor = Cat;
    console.log(Cat.prototype)
    let cat = new Cat('大毛', '黄色');
    console.log(cat)
   // 打印结构    // species, weight, love都能通过原型链获取到
    // color: "黄色"
    // name: "大毛"
    // __proto__: Animal
    //     constructor: ƒ Cat(name, color)
    //     species: "动物"
    //     weight: "19斤"
    //     __proto__:
    //         love: "肉"

四:组合继承(组合原型链继承和构造函数继承)(常用)

实现方式 : 先构造函数继承 再原型链继承

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

    function Animal(weight) {
      this.species = '动物';
      this.weight = weight;
    }
    Animal.prototype.love = '肉'

    function Cat(name, color) {
      Animal.call(this, '80斤');
      this.name = name;
      this.color = color;
    }

    Cat.prototype = new Animal('20斤');
    Cat.prototype.constructor = Cat;
    let cat = new Cat('大毛', '黄色');
    cat
    // color: "黄色"
    // name: "大毛"
    // species: "动物"
    // weight: "80斤"
    // __proto__: Animal
    //     constructor: ƒ Cat(name, color)
    //     species: "动物"
    //     weight: "20斤"
    //         __proto__:
    //            love: "肉"

五: 利用空对象作为中介

实现方式 :F是空对象,所以几乎不占内存,修改Cat的prototype对象,就不会影响到Animal的prototype对象。

缺点:很好了,不错

    function Animal(weight) {
      this.species = '动物';
      this.weight = weight;
    }

    Animal.prototype.love = '肉'

    function Cat(name, color) {
      Animal.call(this, '80斤'); // 
      this.name = name;
      this.color = color;
    }
    function F() { };
    F.prototype = Animal.prototype;
    Cat.prototype = new F();
    Cat.prototype.constructor = Cat;
    let cat = new Cat('大毛', '黄色');

  // 封装成一个继承函数 这个ExtendsFunc函数,就是YUI库如何实现继承的方法。
    function ExtendsFunc(Child, Parent) {
      function F() { };
      F.prototype = Parent.prototype;
      Child.prototype = new F();
      Child.prototype.constructor = Child;
    }

六: 寄生 组合继承(与利用空对象作为中介逻辑 基本一致)

实现方式:继承方式六和 方式五是一样的逻辑代码,写法不一样

缺点:很好了,不错

   function content(obj) {
      function F() { };
      F.prototype = obj;
      F.prototype.constructor = F;
      return new F();
    }
    var con = content(Animal.prototype)
    function Cat(name, color) {
      Animal.call(this, '80斤');
      this.name = name;
      this.color = color;
    }
    Cat.prototype = con;
    con.constructor = Cat;
    var cat = new Cat('大毛', '黄色')

结语:欢迎交流学习