JavaScript类继承本质是原型链模拟,ES6 class为语法糖;原型链继承共享引用属性,构造函数继承避免共享但无法复用方法,组合继承兼顾二者却重复调用父构造,寄生组合式继承优化为最优手动方案,class extends则是其简洁语法糖。

JavaScript 本身没有传统意义上的“类”,但自 ES6 起引入了 class 语法,它本质上仍是基于原型的语法糖。所谓“模拟类继承”,就是用原型机制实现类似 Java/C# 中类与子类之间的继承关系——让子构造函数的实例既能拥有自己的属性,又能访问父构造函数定义的方法和共享行为。
原型链继承:最基础的继承方式
核心是让子类的 prototype 指向父类的一个实例,从而建立原型链。
function Parent() {
this.name = "Parent";
this.colors = ["red", "blue"];
}
Parent.prototype.sayName = function() {
return this.name;
};
function Child() {}
Child.prototype = new Parent(); // 关键:子类原型 = 父类实例
Child.prototype.constructor = Child; // 修复 constructor 指向
const c1 = new Child();
console.log(c1.sayName()); // "Parent"注意点:
- 所有
Child实例共享Parent实例的引用属性(如colors),修改一个会影响其他; - 创建
Child实例时无法给Parent构造函数传参; -
Child.prototype.constructor默认指向Parent,需手动修正。
构造函数继承:解决引用属性共享问题
在子类构造函数中用 call() 或 apply() 调用父类构造函数,把属性“复制”到每个实例上。
立即学习“Java免费学习笔记(深入)”;
function Parent(name) {
this.name = name;
this.colors = ["red", "blue"];
}
function Child(name, age) {
Parent.call(this, name); // 关键:绑定 this,执行父构造函数
this.age = age;
}
const c1 = new Child("Alice", 25);
const c2 = new Child("Bob", 30);
c1.colors.push("green");
console.log(c2.colors); // ["red", "blue"] —— 不受影响局限:
- 只能继承父类构造函数内的属性,无法访问
Parent.prototype上的方法(如sayName); - 方法无法复用,每个实例都有一份副本,浪费内存。
组合继承:兼顾属性独立 + 方法复用
把上面两种方式结合:用构造函数继承实例属性,用原型链继承原型方法。
function Parent(name) {
this.name = name;
this.colors = ["red", "blue"];
}
Parent.prototype.sayName = function() {
console.log(this.name);
};
function Child(name, age) {
Parent.call(this, name); // 第一次调用 Parent(继承属性)
this.age = age;
}
Child.prototype = new Parent(); // 第二次调用 Parent(继承方法)→ 缺陷来源
Child.prototype.constructor = Child;
Child.prototype.sayAge = function() {
console.log(this.age);
};优点: 属性不共享、方法可复用;
缺点: 父类构造函数被调用了两次(一次在 new Parent() 设置原型时,一次在子类内部),略低效。
寄生组合式继承(推荐写法)
避免组合继承中父构造函数重复执行的问题,用 Object.create(Parent.prototype) 替代 new Parent():
function inheritPrototype(Child, Parent) {
const prototype = Object.create(Parent.prototype);
prototype.constructor = Child;
Child.prototype = prototype;
}
function Parent(name) {
this.name = name;
this.colors = ["red", "blue"];
}
Parent.prototype.sayName = function() {
console.log(this.name);
};
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
inheritPrototype(Child, Parent); // 关键:干净地设置原型链
Child.prototype.sayAge = function() {
console.log(this.age);
};这是目前最接近“标准做法”的手动继承方案,也是 Babel 编译 class 继承时底层采用的模式。
ES6 class 继承:简洁可靠的现代写法
class Parent {
constructor(name) {
this.name = name;
this.colors = ["red", "blue"];
}
sayName() {
console.log(this.name);
}
}
class Child extends Parent {
constructor(name, age) {
super(name); // 相当于 Parent.call(this, name)
this.age = age;
}
sayAge() {
console.log(this.age);
}
}extends + super 就是寄生组合式继承的语法糖,语义清晰、逻辑安全,且支持静态方法、getter/setter、instanceof 正常工作。
不复杂但容易忽略细节。


















