你应该要知道的JS继承

是什么?

  • 继承是面向对象技术中的一个概念;
  • 如果一个类继承了另一个类,那么该类就是子类,被继承的类就是父类(超类);
  • 继承后的优点:
    • 子类可以继承父类的所有属性和方法;
    • 子类可以重写属性和方法;

怎么实现?

其实继承的含义非常简单,我们更应该怎么实现继承,继承的方式有那些? 说到继承,我们就会立马想到ES6里面的extends;如果不用extends语法糖,你又能想到哪几种方式呢?

  • 原型链继承
    • 涉及到构造函数,原型,实例之间的关系;
    • 简单来说就是用父构造函数的实例重写子构造函数的原型,那么有原型链的存在,子构造函数的所有实例都能访问到父构造函数的属性和方法;但是原型里面的属性和方法是公共的,任何的修改都会对其他实例造成影响;

你应该要知道的JS继承

  • 构造函数继承
    • 利用call()方法改变this指向;
    • 使用call()方法将父类里面的this指向子类,那么在new一个实例的时候,子类实例里面就有了父构造函数里面的属性和方法;
    • 值得注意的是call()方法必须放在第一行;
    • 使用call()方法,只能继承父构造函数本身的属性和方法,不能继承其原型对象里面定义的属性和方法;会报错;

你应该要知道的JS继承

  • 组合式继承
    • 组合式继承就是将上面两种方式结合起来;
    • call()方法是为获取父类本身的属性和方法;同时这种方式获取属性和方法,子类实例之间的改变不会相互影响,因为实例本身有的话,就不会到原型对象上面去找;
    • 用父构造函数重写子构造函数的原型,是为了获取父构造函数原型对象里面的属性和方法;
    • 在Parent的原型对象上定义方法时,要注意不要用箭头函数,这时候的this是指向window;
    • Parent()执行了两次,造成了性能的浪费;

你应该要知道的JS继承

  • 原型式继承
    • 使用Object.create(proto),主要是对普通对象的继承;
    • 既然用到Object.create()这个方法,那么首先先来了解一下这个方法:
    • Object.create(proto)用于创建一个新的对象,并将传入的对象作为新对象的原型;proto这个参数可以传null;
    • Object.create()是浅拷贝,多个实例的引用数据类型指向相同的内存地址,会相互影响;

你应该要知道的JS继承

  • 寄生式继承
    • 在原型式继承的基础上对创建新的对象的过程进行封装,同时可以为新的对象添加新的属性和方法;
    • 寄生式继承本质上还是多个实例共享同一个原型对象,所以改变属性还是会相互影响;

你应该要知道的JS继承

  • 寄生组合式继承
    • 这种方式算是对组合式继承的一直优化,利用Object.create()方法减少一次对Parent()的调用,优化性能;
    • 总的来说,是最优的继承方案;
    • 使用call()函数继承父类本身的属性和方法;
    • 使用Object.create()方法将父类的原型对象赋值为新对象的原型,这样就能使用父类原型对象里面的属性和方法;同时减少一次Parent()的调用,优化性能;

你应该要知道的JS继承

介绍了这么多实现继承的方法,我相信大家对继承有进一步的认识了;大家肯定会说,这些实现的方式太过于麻烦,并且各有各的问题,无法在实际的开发环境中很好使用;基于这样的问题,ES6中extends语法糖就很好的解决了这个问题;让继承更加的简单,便捷;

  • extends继承
    • 在上面的几种方式中,可以看到都是由构造函数之间实现继承并生成实例,ES6中提供了更接近面向对象的写法,引入了类的概念,使用class定义;
    • ES6的class可以看作是一个语法糖,它的绝大部分的功能,ES5里面的构造函数都可以做到,类只是让原型的写法更加清晰;
    • constructor()构造函数用来定义属性,在类中定义的方法不需要加function,直接使用方法的简写方式;其实直接在类中定义的方法,相当于定义在构造函数的原型对象上;

你应该要知道的JS继承

这就是JS继承的几种方式,当然关于类还有很多的点可以去探讨;

如果各位小伙伴觉得文章还行,希望多多点赞;也可以在评论区列出自己熟悉的JS里面的知识点,互相学习!