JavaScript 中的继承主要基于原型链(Prototype Chain),而不是传统的类继承(如 Java 或 C++)。简单来说,就是让子类能访问到父类的属性和方法。以下是 JavaScript 继承的几种主要实现方式及详细说明:
1. 原型链继承
核心思想:通过将子类的原型对象指向父类的实例,实现属性和方法的继承。
Parent.prototype.say = function () {
console.log('hello')
}
function Parent(age) {
this.name = 'parent';
this.age = age
}
Child.prototype = new Parent() // {name: 'parent', age: 50}.__proto__ === Parent.prototype
function Child(name) {
this.name = name
}
const c = new Child('child') // c.__proto__ === Child.prototype
console.log(c.name); // child
console.log(c.age); // 50
c.say() // hello
问题:
- 引用类型的属性会被所有子类实例共享(如数组、对象)。
- 无法在创建子类实例时向父类构造函数传参。
2. 借用构造函数继承
核心思想:在子类构造函数中调用父类构造函数,通过 call 或 apply 绑定 this。
Parent.prototype.say = function () {
console.log('hello')
}
function Parent(age) {
this.name = 'parent';
this.age = age
}
function Child(name, age) {
Parent.call(this, age)
// 相当于:
// this.name = 'parent';
// this.age = age
this.name = name
}
const c = new Child('child', 50)
console.log(c);
console.log(c.name); // child
console.log(c.age); // 50
// c.say() // hello
优点:
- 解决引用类型属性共享问题。
- 支持向父类构造函数传参。
缺点:
- 无法继承父类原型上的方法(只能继承实例属性)。
3. 组合继承
核心思想:结合原型链继承和构造函数继承,是 JavaScript 中最常用的继承模式。
Parent.prototype.say = function () {
console.log('hello')
}
function Parent(age) {
this.name = 'parent';
this.age = age
}
Child.prototype = new Parent()
function Child(name, age) {
Parent.call(this, age)
this.name = name
}
const c = new Child('child', 50)
console.log(c.name); // child
console.log(c.age); // 50
c.say() // hello
优点:
- 实例属性独立,原型方法共享。
- 支持传参。
缺点:
- 父类构造函数被调用两次,导致子类原型中存在冗余属性。
4. 原型式继承
核心思想:基于已有对象创建新对象,通过 Object.create() 实现。
const obj = {
name: '张三',
age: 40
}
let newObj = Object.create(obj)
console.log(newObj.name);
特点:
- 适用于不需要构造函数的场景。
- 类似原型链继承的引用类型共享问题。
5. 寄生组合继承
核心思想:最优解决方案,通过借用构造函数继承属性,通过原型链混成形式继承方法。
Parent.prototype.say = function () {
console.log('hello')
}
function Parent(age) {
this.name = 'parent';
this.age = age
}
Child.prototype = Object.create(Parent.prototype) // {}
Child.prototype.constructor = Child // 修正构造函数
function Child(name, age) {
Parent.call(this, age)
this.name = name
}
const c = new Child('child', 50)
// console.log(c.name);
// console.log(c.age);
// c.say()
console.log(c.constructor);
优点:
- 只调用一次父类构造函数。
- 避免子类原型上创建冗余属性。
- 原型链保持不变,支持
instanceof操作符。
6. class继承: extends + super()
核心思想:语法糖,底层基于寄生组合式继承。
class Parent {
constructor(name, age) { // 构造函数
this.name = name
this.age = age
}
say() {
console.log('hello');
}
}
class Child extends Parent {
constructor(name, age) {
super(name, age) // 必须调用 super()
this.sex = 'boy'
}
}
const c = new Child('张三', 18)
c.say()
特点:
- 使用
extends继承父类。 super调用父类构造函数或方法。- 支持静态方法继承(
static关键字)。