Skip to content

原型模式

约 819 字大约 3 分钟

设计模式

2018-04-22

什么是原型模式?

Prototype(原型)模式 是一种 创建型设计模式。

其核心思想是通过 复制现有对象(原型对象)来创建新对象,而不是通过类实例化。 在 JavaScript 中,由于语言本身的 基于原型的继承机制,原型模式天然地与对象的行为和继承紧密结合。

提示

原型模式在 JavaScript 中既是设计模式,也是语言核心机制。 它适合高频创建对象和动态扩展的场景,但需警惕共享状态的副作用。 合理利用原型模式,可以显著提升代码复用性和性能,但需结合项目需求权衡是否引入复杂性。

实现原型模式

  • 原型链继承:每个 JavaScript 对象都有一个 [[Prototype]](可通过 __proto__Object.getPrototypeOf() 访问),指向其原型对象。
  • 共享属性和方法:所有实例共享原型对象上的属性和方法,减少重复定义。
  • 动态修改:修改原型对象的属性和方法,会立即反映到所有实例上。
// 原型对象定义
const carPrototype = {
  wheels: 4,
  drive() {
    console.log('Driving...')
  },
}

// 通过 Object.create() 创建新对象(基于原型)
const myCar = Object.create(carPrototype)
myCar.color = 'red'

console.log(myCar.wheels) // 4(继承自原型)
myCar.drive() // "Driving..."

优点

  • 高效内存利用

    原型上的方法和属性被所有实例共享,避免重复创建相同功能的方法,节省内存。

  • 动态性和灵活性

    运行时可以动态修改原型,所有实例自动继承变更。

  • 避免重复代码

    通过复用原型,减少冗余代码(例如构造函数中重复绑定方法)。

  • 天然支持 JavaScript 继承

    与 JavaScript 的原型链机制无缝结合,是语言原生特性的直接应用。

缺点

  • 共享状态的风险

    如果原型属性是引用类型(如数组、对象),所有实例会共享同一份数据。

  • 原型链复杂性

    深层次的原型链可能导致属性查找性能下降(需逐级向上搜索)。

    多重继承或复杂原型链可能使代码难以维护。

  • 覆盖问题

    实例可以覆盖原型属性,可能导致意外行为:

    const c = Object.create(carPrototype)
    c.wheels = 3 // 覆盖原型属性
    console.log(c.wheels) // 3(实例属性优先于原型)

适用场景

  • 需要创建大量相似对象

    例如游戏中的 NPC 敌人、粒子系统等高频创建的场景,复用原型节省内存。

  • 动态扩展对象功能

    在运行时为所有实例添加/修改功能(如日志功能、监控逻辑)。

  • 替代类继承

    当类继承导致复杂层次结构时,原型模式更轻量灵活。

  • Object.create() 结合使用

    明确指定原型对象,避免构造函数和 new 关键字的限制。

最佳实践

  • 避免共享引用类型属性:将引用类型属性定义在构造函数中,而非原型。
  • 浅拷贝/深拷贝:需要完全独立对象时,使用 Object.assign() 或深拷贝工具。
  • ES6 Class 语法糖:底层仍基于原型,但提供更清晰的抽象。