ES6 之前 JS 如何实现继承
ES6 之前的继承是通过原型来实现的,也就是每一个构造函数都会有一个 prototype 属性,调用实例的方法或属性时,首先在自身上寻找,再去构造函数的 prototype 上寻找;prototype 本质上也是一个对象实例,如果还没找到,会继续沿原型链上溯到 Object.prototype,最终到 null。
实现继承的核心就是让子类的原型指向父类的一个实例,从而形成原型链。
寄生组合式继承(最常用方案)
function Parent(name) {
this.name = name;
}
Parent.prototype.say = function () {
console.log('hi, ' + this.name);
};
function Child(name, age) {
Parent.call(this, name); // 1. 继承父类实例属性
this.age = age;
}
// 2. 继承父类原型方法(关键:用 Object.create,避免调用 Parent 构造函数)
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child; // 修正 constructor 指向
const c = new Child('Tom', 18);
c.say(); // hi, Tom
补充:原型链继承的几种典型写法与对比:
- 原型链继承:直接把
Child.prototype = new Parent(),问题:父类引用类型属性被所有子类共享,且Parent被调用了一次无法传参。 - 构造函数继承:在子类构造里
Parent.call(this, ...),问题:方法都建在实例上,无法复用。 - 组合继承:上面两者结合,但
Parent仍会被调用两次(一次在原型上、一次在构造里)。 - 寄生组合式继承:通过
Object.create(Parent.prototype)拿一个干净的父类原型副本,避免Parent多余调用,是目前最合理的方式,也是 ES6class的底层实现思路。 - ES6
class extends:本质上是寄生组合式继承的语法糖,强烈推荐。
来源整理自:vue3js.cn 面试官系列



