准确地说,JS 中没有 类 的概念,有的只是 构造函数 和 原型链。不过,我们可以通过构造函数和原型链来实现类似于类的继承,并且可以玩出很多花样、实现不同的特性。
直接把要继承的构造函数的 prototype
指向一个实例化的父类对象即可。
优点:简单易懂,符合原型链的基本思想
缺点:
- 如果弗雷包含引用类型的属性(如数组),子类实例对这个属性的修改影响其他子类实例, 因为是以引用的方式继承的 。
- 在创建子类实例时,不能向父类构造函数传递参数。
直接调用父类构造函数的 Function.prototype.call
方法,指定 this
和参数即可。
优点:
- 避免了引用类型的属性共享问题,传入的值直接在这个实例中单独初始化。
- 可以在创建子类实例时向父类传递参数。
缺点:
- 方法都在构造函数中定义,无法直接的实现函数复用,每个实例都有自己独立的方法副本。
在子类构造函数内部先用 call
绑定 this
,然后再指定子类构造函数的 prototype
为父类的实例,最后把 prototype.constructor
指向自己。
优点:结合了原型链继承和构造函数继承的优点,避免了它们各自的缺点。
缺点:调用了 两次 父类构造函数,导致子类原型上 多了不需要的父类属性 。
使用 Object.create
方法来创建一个子类对象。
优点:不需要定义构造函数,只需要指定要继承的对象,就可以创建对象。
缺点:和原型链继承一样,引用类型的属性会被共享。
提供了一个返回子类实例的函数,在其内部调用 Object.create
方法创建子类实例,并为其指定相关属性,之后将其返回。
优点:可以在不必为新对象构建自定义类型的情况下,实现对象的属性继承。
缺点:和原型链继承一样,引用类型的属性会被共享。
引入一个函数 inheritPrototype
,传入子类构造函数和父类构造函数,将两者的 prototype
绑定到一起(类似于 new
操作符)。
其余的部分和构造函数继承类似。
优点:解决了组合继承中调用两次父类构造函数的问题,避免了不必要的属性初始化。
缺点:相对于其他方式,寄生组合式继承是比较完善的一种继承方式,但是在方法实现上相对比较复杂。