🧩 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,底层就是寄生组合继承。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐