前端面试 P035:继承方式对照与寄生组合式继承
Showing the original in Chinese (China)
来源:方格前端讲面试 · 35. JS 中常见继承方式对比总结,24 分 40 秒。
回看定位:04:41 原型链继承 · 13:23 组合继承 · 16:09 寄生组合式 · 20:26 class
把实例状态与方法共享分开
| 方式 | 做法 | 主要限制 |
|---|---|---|
| 原型链继承 | Child.prototype = new Parent(...) | 父实例上的可变属性被子实例共享;建立原型时调用父构造器 |
| 借用构造器 | Child 内 Parent.call(this, ...) | 初始化自有属性,单独使用不连接父原型方法链 |
| 组合继承 | 借用构造器并 new Parent 建立原型 | 建链和实例初始化都会调用父构造器,原型可能带多余实例状态 |
| 寄生组合式 | Object.create(Parent.prototype) 建链,加父初始化 | 适合普通函数构造体系,不自动等同现代 class 完整语义 |
| class extends | 使用标准类继承与 super | 仍应控制层级、共享状态与子类契约 |
视频说设置原型时“无法给 Parent 传参”需精确化:new Parent(arg) 当然能传参数;问题是这次发生在公共原型建立阶段,不能为未来每个子实例分别初始化所需状态。
普通函数的寄生组合式示例
function Parent(name) {
this.name = name;
this.items = [];
}
Parent.prototype.read = function () { return this.name; };
function Child(name) { Parent.call(this, name); }
Child.prototype = Object.create(Parent.prototype, {
constructor: { value: Child, writable: true, configurable: true },
});
const a = new Child('A');
const b = new Child('B');
a.items.push(1);
console.log(b.items.length); // 0
console.log(a.read()); // A
console.log(a instanceof Parent); // true
console.log(a instanceof Child); // true
Object.create 不调用 Parent,公共原型不必包含父实例的数据。constructor 属性只是惯用元信息,修复它不会自行决定 new 的构造行为。
与 class 的关键区别
不要把 super() 等同 Parent.call(this):派生类可能先由父构造过程产生 this,class 构造器不能普通调用,静态继承、new.target、内建对象构造也有差异。传统寄生组合式还不会自动连好 Child 类对象到 Parent 的静态继承链。
“最优继承方式”是特定时代和约束下的评价。现代代码优先使用清晰的标准结构;如果只是共享几种能力,组合函数或委派可能比深层继承更易维护。
关联:前端面试 P033:Object.create、描述符与共享属性、前端面试 P034:class、super 与语法糖的边界。