1. 寄生组合继承(Parasitic Combination Inheritance)
实现方式
js
// 父类
function Parent(name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.sayName = function() {
console.log('Parent name:', this.name);
};
Parent.prototype.sayColors = function() {
console.log('Parent colors:', this.colors);
};
// 子类
function Child(name, age) {
// 构造函数继承(继承实例属性)
Parent.call(this, name);
this.age = age;
}
// 原型继承(继承方法)
function inheritPrototype(child, parent) {
// 创建父类原型的副本
const prototype = Object.create(parent.prototype);
// 修复 constructor 指向
prototype.constructor = child;
// 设置子类原型
child.prototype = prototype;
}
// 应用寄生组合继承
inheritPrototype(Child, Parent);
// 添加子类方法
Child.prototype.sayAge = function() {
console.log('Child age:', this.age);
};
// 使用示例
const child1 = new Child('Alice', 10);
child1.colors.push('black');
child1.sayName(); // Parent name: Alice
child1.sayAge(); // Child age: 10
child1.sayColors(); // Parent colors: ["red", "blue", "green", "black"]
const child2 = new Child('Bob', 12);
child2.sayColors(); // Parent colors: ["red", "blue", "green"]
2. ES6 类继承
实现方式
js
// 父类
class Parent {
constructor(name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
sayName() {
console.log('Parent name:', this.name);
}
sayColors() {
console.log('Parent colors:', this.colors);
}
// 静态方法
static staticMethod() {
console.log('This is a static method');
}
}
// 子类
class Child extends Parent {
constructor(name, age) {
super(name); // 必须调用 super
this.age = age;
}
sayAge() {
console.log('Child age:', this.age);
}
// 重写父类方法
sayName() {
super.sayName(); // 调用父类方法
console.log('And I am a child');
}
// 静态方法也可以继承
static childStaticMethod() {
super.staticMethod();
console.log('Child static method');
}
}
// 使用示例
const child1 = new Child('Alice', 10);
child1.colors.push('black');
child1.sayName(); // Parent name: Alice \n And I am a child
child1.sayAge(); // Child age: 10
child1.sayColors(); // Parent colors: ["red", "blue", "green", "black"]
Child.childStaticMethod(); // 静态方法调用
3. 详细对比
| 特性 | 寄生组合继承 | ES6 类继承 |
|---|---|---|
| 语法 | 函数 + 原型 | 类语法糖 |
| 可读性 | 较低 | 高 |
| 继承原理 | 原型链 + 构造函数 | 基于原型链 |
| 静态方法 | 需手动处理 | 原生支持 |
| 私有字段 | 无直接支持 | ES2022+ 支持 |
| super 调用 | 需手动实现 | 原生支持 |
| new.target | 不支持 | 支持 |
| constructor | 需手动设置 | 自动设置 |
4. 性能对比
js
// 性能测试
class PerformanceTest {
static testParasitic() {
const start = performance.now();
function Parent(name) {
this.name = name;
}
Parent.prototype.getName = function() { return this.name; };
function Child(name) {
Parent.call(this, name);
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
for (let i = 0; i < 1000000; i++) {
new Child('test' + i);
}
return performance.now() - start;
}
static testES6() {
const start = performance.now();
class Parent {
constructor(name) { this.name = name; }
getName() { return this.name; }
}
class Child extends Parent {
constructor(name) { super(name); }
}
for (let i = 0; i < 1000000; i++) {
new Child('test' + i);
}
return performance.now() - start;
}
}
console.log('寄生组合继承耗时:', PerformanceTest.testParasitic().toFixed(2), 'ms');
console.log('ES6 类继承耗时:', PerformanceTest.testES6().toFixed(2), 'ms');
// 输出:
// 寄生组合继承耗时: 26.49 ms
// ES6 类继承耗时: 13.97 ms
性能结果:
- ES6 类继承通常更快(V8 优化)
- 寄生组合继承稍慢但差异很小
- 实际应用差异可忽略不计
5. 特性详解
5.1 原型链
js
// 寄生组合继承
const child1 = new Child('Alice', 10);
console.log(child1.__proto__ === Child.prototype); // true
console.log(child1.__proto__.__proto__ === Parent.prototype); // true
console.log(child1 instanceof Child); // true
console.log(child1 instanceof Parent); // true
console.log(child1 instanceof Object); // true
// ES6 类继承
const child2 = new Child('Bob', 12);
console.log(Object.getPrototypeOf(child2) === Child.prototype); // true
console.log(Object.getPrototypeOf(Object.getPrototypeOf(child2)) === Parent.prototype); // true
console.log(child2 instanceof Child); // true
console.log(child2 instanceof Parent); // true
5.2 静态成员继承
js
// 寄生组合继承(需手动实现)
function Animal() {}
Animal.staticMethod = function() { return 'Animal static'; };
function Dog() {}
Dog.__proto__ = Animal; // 继承静态方法
Dog.staticMethod(); // 'Animal static'
// 或
Object.setPrototypeOf(Dog, Animal);
// ES6 类继承(自动继承)
class Animal {
static staticMethod() { return 'Animal static'; }
}
class Dog extends Animal {
static dogStatic() { return 'Dog static'; }
}
console.log(Dog.staticMethod()); // 'Animal static'
console.log(Dog.dogStatic()); // 'Dog static'
console.log(Object.getPrototypeOf(Dog) === Animal); // true
5.3 方法重写
js
// 寄生组合继承
function Animal() {}
Animal.prototype.speak = function() { return 'Animal sound'; };
function Dog() {}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
// 重写方法
Dog.prototype.speak = function() {
// 调用父类方法
const parentSpeak = Animal.prototype.speak.call(this);
return parentSpeak + ' and Woof!';
};
// ES6 类继承
class Animal {
speak() { return 'Animal sound'; }
}
class Dog extends Animal {
speak() {
return super.speak() + ' and Woof!';
}
}
6. 优缺点对比
寄生组合继承的优点
- 兼容性极好:支持所有浏览器
js
// IE6+ 都支持
if (typeof Object.create !== 'function') {
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
- 更灵活:手动控制继承逻辑
js
// 可以选择性继承
function createMixin(baseClass, mixin) {
function MixedClass() {
baseClass.call(this);
mixin.call(this);
}
MixedClass.prototype = Object.create(baseClass.prototype);
Object.assign(MixedClass.prototype, mixin.prototype);
return MixedClass;
}
- 内存效率:可优化原型链深度
js
// 扁平化原型链
function createFlatInheritance(parent, child) {
// 合并原型方法,减少查找深度
for (let key in parent.prototype) {
if (parent.prototype.hasOwnProperty(key)) {
child.prototype[key] = parent.prototype[key];
}
}
}
寄生组合继承的缺点
- 语法繁琐,易出错
- 私有字段不支持,需用闭包模拟
- 静态方法需手动处理
- 可读性差
ES6 类继承的优点
- 语法简洁,易于理解
js
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
get area() { return this.height * this.width; }
}
- 内置 super,方便调用父类
js
class Square extends Rectangle {
constructor(side) {
super(side, side);
}
get area() {
console.log('Calculating square area...');
return super.area;
}
}
- 支持静态方法和字段
js
class MyClass {
static staticField = 'static';
static staticMethod() { return 'static method'; }
#privateField = 'private';
}
- 更好的工具支持(TypeScript、IDE)
ES6 类继承的缺点
- 语法糖,实际还是原型继承
- 必须用 new 调用 ,不能当普通函数31. 没有私有方法(ES2022+ 才有)
- 兼容性:旧浏览器需转译
- 某些特性限制:
js
class MyClass {
constructor() {
this.method = () => { /* 箭头函数,this 绑定 */ };
}
// 不能这样写:
// property = () => { }; // ES7+ 才支持
}
7. 转译结果对比
Babel 转译 ES6 类继承
js
// ES6
class Parent {
constructor(name) { this.name = name; }
say() { console.log(this.name); }
}
class Child extends Parent {
constructor(name, age) {
super(name);
this.age = age;
}
}
// Babel 转译后
"use strict";
function _inherits(subClass, superClass) {
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: { value: subClass, writable: true, configurable: true }
});
Object.setPrototypeOf(subClass, superClass);
}
function _createSuper(Derived) {
return function _createSuperInternal() {
var Super = _getPrototypeOf(Derived);
var result = Reflect.construct(Super, arguments, _getPrototypeOf(this).constructor);
return _possibleConstructorReturn(this, result);
};
}
var Parent = function Parent(name) {
this.name = name;
};
Parent.prototype.say = function say() {
console.log(this.name);
};
var Child = /*#__PURE__*/function (_Parent) {
_inherits(Child, _Parent);
var _super = _createSuper(Child);
function Child(name, age) {
var _this;
_this = _super.call(this, name);
_this.age = age;
return _this;
}
return Child;
}(Parent);
8. 实际应用建议
适合使用寄生组合继承的场景
js
// 1. 需要支持 IE 的项目
if (typeof window !== 'undefined' &&
/MSIE|Trident/.test(window.navigator.userAgent)) {
// 使用寄生组合继承
function IECompatibleClass() {}
}
// 2. 需要深度定制继承逻辑
function createCustomInheritance(SuperClass, mixins) {
function CustomClass() {
SuperClass.apply(this, arguments);
mixins.forEach(mixin => {
mixin.init && mixin.init.apply(this, arguments);
});
}
CustomClass.prototype = Object.create(SuperClass.prototype);
mixins.forEach(mixin => {
Object.assign(CustomClass.prototype, mixin.methods);
});
return CustomClass;
}
适合使用 ES6 类继承的场景
js
// 1. 现代前端框架
import React from 'react';
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
render() {
return <div>{this.state.count}</div>;
}
}
// 2. Node.js 服务端
class DatabaseService {
constructor(config) {
this.config = config;
}
async connect() { /* ... */ }
}
class MySQLService extends DatabaseService {
async query(sql) { /* ... */ }
}
// 3. 需要类型检查
class Person {
constructor(name) {
if (typeof name !== 'string') {
throw new Error('Name must be a string');
}
this.name = name;
}
}
9. 混合使用模式(一般用不到)
js
// 结合两种方式
// 使用类作为基础
class EventEmitter {
constructor() {
this.events = {};
}
on(event, listener) {
(this.events[event] || (this.events[event] = [])).push(listener);
}
emit(event, ...args) {
(this.events[event] || []).forEach(listener => listener(...args));
}
}
// 使用寄生组合继承扩展
function createObservable(SuperClass) {
function Observable() {
SuperClass.apply(this, arguments);
this.observers = [];
}
Observable.prototype = Object.create(SuperClass.prototype);
Observable.prototype.constructor = Observable;
Observable.prototype.subscribe = function(observer) {
this.observers.push(observer);
};
Observable.prototype.notify = function(data) {
this.observers.forEach(observer => observer(data));
};
return Observable;
}
// 组合使用
class Model extends createObservable(EventEmitter) {
constructor(data) {
super();
this.data = data;
}
set(key, value) {
this.data[key] = value;
this.notify({ key, value });
this.emit('change', { key, value });
}
}
10. 最佳实践
现代项目
js
// 使用 ES6 类继承
class BaseService {
constructor(config) {
this.config = config;
}
validateConfig() {
// 验证配置
}
async init() {
throw new Error('Method not implemented');
}
}
class ApiService extends BaseService {
constructor(config) {
super(config);
this.validateConfig();
}
async init() {
// 实现初始化
}
}
需要兼容性的项目
js
// 使用模块化的寄生组合继承
function createClass(superClass, definition) {
const Child = definition.constructor || function() {
superClass.apply(this, arguments);
};
// 原型继承
Child.prototype = Object.create(superClass.prototype);
Child.prototype.constructor = Child;
// 混入方法
if (definition.methods) {
Object.assign(Child.prototype, definition.methods);
}
// 静态方法继承
Object.setPrototypeOf(Child, superClass);
// 添加静态方法
if (definition.statics) {
Object.assign(Child, definition.statics);
}
return Child;
}
总结
| 方面 | 推荐选择 | 原因 |
|---|---|---|
| 现代 Web 项目 | ES6 类继承 | 语法简洁,工具支持好 |
| 库/框架开发 | ES6 类继承 | 更好的开发体验 |
| 需要支持旧 IE | 寄生组合继承 | 兼容性好 |
| 性能关键 | ES6 类继承 | 现代引擎优化好 |
| 代码可读性 | ES6 类继承 | 语法更清晰 |
| 团队熟悉度 | 团队熟悉的 | 降低学习成本 |
最终建议:
- 新项目一律使用 ES6 类继承
- 旧项目维护时,如果已经是寄生组合继承,可保持
- 需要特殊继承模式时,可混用两种方式
- 始终考虑团队成员技能和项目需求