JavaScript作为一门基于原型的编程语言,本身没有传统面向对象语言中的类继承概念,但可以通过多种方式模拟实现继承效果,满足代码复用和对象关系构建的需求。

原型链继承
原型链继承是JavaScript中最基础的继承实现方式,核心是利用原型链的查找机制,让子类型的原型指向父类型的实例,这样子类型的实例就能访问到父类型原型上的属性和方法。
// 定义父类型构造函数
function Parent() {
this.parentName = '父类属性';
}
// 父类型原型上添加方法
Parent.prototype.getParentName = function() {
return this.parentName;
};
// 定义子类型构造函数
function Child() {
this.childName = '子类属性';
}
// 子类型原型指向父类型实例,实现继承
Child.prototype = new Parent();
// 修正子类型原型的构造函数指向,避免指向Parent
Child.prototype.constructor = Child;
// 子类型原型上添加自己的方法
Child.prototype.getChildName = function() {
return this.childName;
};
// 测试继承效果
const childInstance = new Child();
console.log(childInstance.getParentName()); // 输出:父类属性
console.log(childInstance.getChildName()); // 输出:子类属性这种方式的优点是实现简单,能复用父类型原型上的方法,但缺点也很明显:所有子类型实例会共享父类型实例的引用属性,修改一个实例的引用属性会影响其他实例,而且无法在创建子类型实例时给父类型构造函数传参。
构造函数继承
构造函数继承也叫经典继承,核心是在子类型构造函数内部调用父类型构造函数,通过call或apply方法改变父类型构造函数的this指向,让父类型的属性在子类型实例上初始化。
// 定义父类型构造函数
function Parent(name) {
this.name = name;
this.hobbies = ['读书', '运动'];
}
// 父类型原型上添加方法
Parent.prototype.sayName = function() {
return this.name;
};
// 定义子类型构造函数
function Child(name, age) {
// 调用父类型构造函数,传入当前子类型实例作为this,实现属性继承
Parent.call(this, name);
this.age = age;
}
// 测试继承效果
const child1 = new Child('小明', 10);
const child2 = new Child('小红', 12);
child1.hobbies.push('画画');
console.log(child1.hobbies); // 输出:['读书', '运动', '画画']
console.log(child2.hobbies); // 输出:['读书', '运动']
console.log(child1.sayName); // 输出:undefined,无法继承父类型原型上的方法这种方式的优点是可以给父类型构造函数传参,每个子类型实例的属性都是独立的,不会互相影响,但缺点是无法继承父类型原型上的方法,方法只能定义在构造函数中,无法实现函数复用,每个实例都会创建一份相同的方法副本,浪费内存。
组合继承
组合继承是将原型链继承和构造函数继承结合起来的方式,既通过原型链继承父类型原型上的方法,又通过构造函数继承父类型的实例属性,是目前JavaScript中比较常用的继承方式之一。
// 定义父类型构造函数
function Parent(name) {
this.name = name;
this.hobbies = ['读书', '运动'];
}
// 父类型原型上添加方法
Parent.prototype.sayName = function() {
return this.name;
};
// 定义子类型构造函数
function Child(name, age) {
// 构造函数继承,继承实例属性
Parent.call(this, name);
this.age = age;
}
// 原型链继承,继承原型上的方法
Child.prototype = new Parent();
// 修正构造函数指向
Child.prototype.constructor = Child;
// 测试继承效果
const child1 = new Child('小明', 10);
const child2 = new Child('小红', 12);
child1.hobbies.push('画画');
console.log(child1.hobbies); // 输出:['读书', '运动', '画画']
console.log(child2.hobbies); // 输出:['读书', '运动']
console.log(child1.sayName()); // 输出:小明
console.log(child2.sayName()); // 输出:小红组合继承融合了两种继承方式的优点,既能保证实例属性独立,又能复用原型上的方法,但缺点是会调用两次父类型构造函数,一次是在设置子类型原型时,一次是在子类型构造函数内部,会存在一些不必要的属性开销。
寄生组合继承
寄生组合继承是对组合继承的优化,核心是不通过调用父类型构造函数来创建子类型的原型,而是直接复制父类型原型的副本作为子类型的原型,避免了组合继承中两次调用父类型构造函数的问题,是业内公认的比较理想的继承实现方式。
// 定义父类型构造函数
function Parent(name) {
this.name = name;
this.hobbies = ['读书', '运动'];
}
// 父类型原型上添加方法
Parent.prototype.sayName = function() {
return this.name;
};
// 辅助函数:复制父类型原型创建子类型原型
function inheritPrototype(child, parent) {
// 创建父类型原型的副本
const prototype = Object.create(parent.prototype);
// 修正副本的构造函数指向子类型
prototype.constructor = child;
// 将副本赋值给子类型的原型
child.prototype = prototype;
}
// 定义子类型构造函数
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
// 调用辅助函数实现继承
inheritPrototype(Child, Parent);
// 测试继承效果
const child1 = new Child('小明', 10);
const child2 = new Child('小红', 12);
child1.hobbies.push('画画');
console.log(child1.hobbies); // 输出:['读书', '运动', '画画']
console.log(child2.hobbies); // 输出:['读书', '运动']
console.log(child1.sayName()); // 输出:小明
console.log(child2.sayName()); // 输出:小红这种方式只调用一次父类型构造函数,既保证了属性独立,又复用了原型方法,没有多余的开销,适合大多数场景的继承需求。
ES6 class继承
ES6引入了class语法糖,让JavaScript的继承写法更接近传统面向对象语言的类继承,底层本质还是基于原型链实现,但语法更加简洁清晰,是目前开发中最推荐的继承写法。
// 定义父类
class Parent {
constructor(name) {
this.name = name;
this.hobbies = ['读书', '运动'];
}
// 父类方法
sayName() {
return this.name;
}
}
// 定义子类,通过extends关键字继承父类
class Child extends Parent {
constructor(name, age) {
// 调用super方法执行父类构造函数,必须在使用this之前调用
super(name);
this.age = age;
}
// 子类自己的方法
sayAge() {
return this.age;
}
}
// 测试继承效果
const child1 = new Child('小明', 10);
const child2 = new Child('小红', 12);
child1.hobbies.push('画画');
console.log(child1.hobbies); // 输出:['读书', '运动', '画画']
console.log(child2.hobbies); // 输出:['读书', '运动']
console.log(child1.sayName()); // 输出:小明
console.log(child1.sayAge()); // 输出:10ES6的class继承语法简洁,内置了构造函数指向修正和原型链构建的逻辑,避免了手动操作的繁琐和出错概率,同时支持super关键字调用父类方法,开发体验更好,在支持ES6的环境下优先使用这种方式。
JavaScript继承原型链构造函数ES6_class修改时间:2026-06-05 01:54:26