一、原型链继承
原理
通过将 子类构造函数的原型(prototype
) 指向 父类实例,实现继承链。
示例
javascript
// 父类
function Animal(name) {
this.name = name || 'Animal';
this.colors = ['black', 'white'];
}
Animal.prototype.say = function() {
console.log(`I'm ${this.name}`);
};
// 子类
function Cat() {}
Cat.prototype = new Animal(); // 原型链继承
// 测试
const cat1 = new Cat();
cat1.say(); // I'm Animal(继承父类方法)
cat1.colors.push('orange');
console.log(cat1.colors); // ['black', 'white', 'orange']
const cat2 = new Cat();
console.log(cat2.colors); // ['black', 'white', 'orange'](引用类型属性被共享!)
特点
-
优点:简单易实现,可继承父类实例属性及原型方法。
-
缺点:
- 所有子类实例共享父类实例的 引用类型属性 (如
colors
数组)。 - 无法向父类构造函数传递参数(如
name
参数在子类中无法自定义)。
- 所有子类实例共享父类实例的 引用类型属性 (如
二、构造函数继承(借用构造函数)
原理
在子类构造函数中通过 call
或 apply
调用父类构造函数,继承父类实例属性。
示例
javascript
// 父类
function Animal(name) {
this.name = name || 'Animal';
this.colors = ['black', 'white'];
}
Animal.prototype.say = function() {
console.log(`I'm ${this.name}`);
};
// 子类
function Cat(name) {
Animal.call(this, name); // 构造函数继承(可传参)
}
// 测试
const cat1 = new Cat('Tom');
cat1.colors.push('orange');
console.log(cat1.colors); // ['black', 'white', 'orange']
console.log(cat1.name); // Tom(参数传递成功)
const cat2 = new Cat('Jerry');
console.log(cat2.colors); // ['black', 'white'](引用类型属性独立!)
cat1.say(); // TypeError: cat1.say is not a function(无法继承父类原型方法!)
特点
-
优点:
- 解决引用类型属性共享问题。
- 支持向父类构造函数传递参数。
-
缺点 :无法继承父类原型上的方法(如
say
方法)。
三、ES6 Class 类继承
原理
通过 extends
和 super
关键字实现继承,底层基于 寄生组合继承,语法更简洁。
示例
javascript
// 父类
class Animal {
constructor(name) {
this.name = name || 'Animal';
this.colors = ['black', 'white'];
}
say() {
console.log(`I'm ${this.name}`);
}
}
// 子类
class Cat extends Animal {
constructor(name) {
super(name); // 调用父类构造函数
this.age = 2;
}
// 可扩展子类方法
meow() {
console.log('Meow!');
}
}
// 测试
const cat1 = new Cat('Tom');
cat1.say(); // I'm Tom(继承父类方法)
cat1.colors.push('orange');
console.log(cat1.colors); // ['black', 'white', 'orange']
const cat2 = new Cat('Jerry');
console.log(cat2.colors); // ['black', 'white'](引用类型属性独立!)
cat2.meow(); // Meow!(子类自定义方法)
特点
-
优点:
- 语法简洁,完全面向对象。
- 解决引用类型共享问题,支持传参。
- 自动继承父类原型方法。
-
底层实现 :
class
继承本质上是通过 寄生组合继承 实现,避免构造函数重复调用,性能最优。
四、对比总结
继承方式 | 核心原理 | 优点 | 缺点 |
---|---|---|---|
原型链继承 | 子类原型指向父类实例 | 简单,可继承父类原型方法 | 引用类型属性共享,无法传参 |
构造函数继承 | 子类构造函数中调用父类构造函数 | 解决属性共享问题,支持传参 | 无法继承父类原型方法 |
ES6 Class 继承 | 基于 extends 和 super 的语法糖 |
语法简洁,解决所有继承问题,性能最优 | 需支持 ES6 环境 |