【JavaScript】继承
·
🧩 JavaScript 中的继承方案全览
1. 原型链继承(Prototype Chain Inheritance)
核心:子类的原型对象 = 父类的实例。
function Parent() {
this.colors = ["red", "green"]
}
Parent.prototype.sayHi = function() {
console.log("Hi")
}
function Child() {}
Child.prototype = new Parent()
let c1 = new Child()
let c2 = new Child()
c1.colors.push("blue")
console.log(c2.colors) // ["red","green","blue"] ← 引用属性被共享
✅ 优点:
- 子类能访问父类的方法。
❌ 缺点:
- 父类引用类型属性会被所有实例共享(问题大)。
- 无法向
Parent传参。
2. 借用构造函数继承(Constructor Stealing / Classical Inheritance)
核心:在子类构造函数里调用父类构造函数。
function Parent(name) {
this.name = name
this.colors = ["red", "green"]
}
function Child(name, age) {
Parent.call(this, name) // 借用构造函数
this.age = age
}
let c1 = new Child("Tom", 10)
let c2 = new Child("Jerry", 12)
c1.colors.push("blue")
console.log(c1.colors) // ["red","green","blue"]
console.log(c2.colors) // ["red","green"]
✅ 优点:
- 解决了共享引用属性的问题。
- 子类可向父类传参。
❌ 缺点:
- 方法都在父类构造函数里定义,每次实例化都会创建一份 → 无法复用方法。
3. 组合继承(Combination Inheritance)
核心:= 原型链继承 + 借用构造函数继承。
function Parent(name) {
this.name = name
this.colors = ["red", "green"]
}
Parent.prototype.sayName = function() {
console.log(this.name)
}
function Child(name, age) {
Parent.call(this, name) // 借用构造函数
this.age = age
}
Child.prototype = new Parent() // 原型链继承
Child.prototype.constructor = Child
let c1 = new Child("Tom", 10)
let c2 = new Child("Jerry", 12)
c1.sayName() // "Tom"
✅ 优点:
- 方法复用(放在
prototype)。 - 属性独立(用
call)。
❌ 缺点:
Parent构造函数被调用了两次(一次call,一次new Parent()),性能浪费。
4. 原型式继承(Prototypal Inheritance)
核心:用一个函数包装对象克隆。
function createObj(o) {
function F() {}
F.prototype = o
return new F()
}
let parent = { name: "Tom", colors: ["red"] }
let child = createObj(parent)
child.colors.push("blue")
console.log(parent.colors) // ["red","blue"] ← 共享了引用属性
✅ 优点:
- 本质就是浅拷贝,适合只需要继承对象的情况。
❌ 缺点:
- 共享引用属性问题依旧。
👉 ES5 提供了 Object.create(),就是这个模式的原生实现。
5. 寄生式继承(Parasitic Inheritance)
核心:在原型式继承基础上增强。
function createEnhancedObj(o) {
let clone = Object.create(o) // 原型式继承
clone.sayHi = function() { // 增强
console.log("Hi")
}
return clone
}
✅ 优点:
- 灵活,可以给对象增强方法。
❌ 缺点:
- 方法依然无法复用(每次都新建)。
6. 寄生组合继承(Parasitic Combination Inheritance)
核心:优化组合继承,避免父类构造函数调用两次。
👉 ES6 class extends 的本质实现方式。
function Parent(name) {
this.name = name
this.colors = ["red", "green"]
}
Parent.prototype.sayName = function() {
console.log(this.name)
}
function Child(name, age) {
Parent.call(this, name) // 借用构造函数
this.age = age
}
// 关键:只继承父类原型,不调用构造函数
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child
✅ 优点:
- 父类构造函数只调用一次。
- 方法复用 + 属性独立。
- 性能最佳 → 推荐 ES5 的继承方式。
7. ES6 class 继承
核心:语法糖,背后就是寄生组合继承。
class Parent {
constructor(name) {
this.name = name
this.colors = ["red", "green"]
}
sayName() {
console.log(this.name)
}
}
class Child extends Parent {
constructor(name, age) {
super(name) // 相当于 Parent.call(this, name)
this.age = age
}
}
let c1 = new Child("Tom", 10)
c1.sayName() // "Tom"
✅ 优点:
- 语法简洁,符合传统面向对象语言习惯。
- 背后依旧是
Object.create+super。
❌ 缺点:
- 本质还是原型继承,不是“真正的类继承”。
🔑 总结表格
| 继承方式 | 代码写法 | 优点 | 缺点 |
|---|---|---|---|
| 原型链继承 | Child.prototype = new Parent() |
简单,可复用方法 | 引用属性共享,不能传参 |
| 构造函数继承 | Parent.call(this) |
属性独立,可传参 | 方法不能复用 |
| 组合继承 | call + new Parent() |
方法复用+属性独立 | 调用两次父构造函数 |
| 原型式继承 | Object.create(obj) |
简单 | 引用属性共享 |
| 寄生式继承 | Object.create(obj)+增强 |
灵活 | 方法不复用 |
| 寄生组合继承 | call + Object.create |
完美:高效+灵活 | 语法稍繁琐 |
| ES6 class | class Child extends Parent |
简洁优雅 | 本质还是原型链 |
✅ 一句话总结:
- ES5 推荐 寄生组合继承。
- ES6 直接用
class extends,底层就是寄生组合继承。
更多推荐


所有评论(0)