编写可预测的函数原型需确保属性初始化顺序、类型一致,构造函数中一次性声明所有实例属性;方法须在定义后立即挂载到 prototype,禁用运行时原型修改;优先使用 class 语法与稳定继承链,避免 Object.setPrototypeOf() 和 __proto__。

编写可预测的函数原型,核心在于让 JavaScript 引擎(如 V8)能稳定内联缓存(IC)并避免隐藏类(hidden class)频繁变更。关键不是“手动优化原型链”,而是通过一致的属性访问模式和构造逻辑,让引擎能高效推测对象结构与方法位置。
保持构造函数中属性初始化顺序与类型一致
引擎会为每个构造函数生成隐藏类。若不同实例在初始化时添加属性的顺序、数量或类型不一致,会触发隐藏类分裂,导致后续原型方法查找无法复用 IC 缓存。
- 始终在构造函数开头一次性声明所有实例属性,哪怕初始值为
null或undefined - 避免在条件分支中动态添加属性(例如
if (x) this.a = 1),改用统一赋值 + 后续逻辑判断 - 同一属性尽量保持相同类型(如始终为 number 或始终为 string),避免
this.count = 0后又赋值this.count = "zero"
避免在运行时修改原型对象
向 prototype 添加、删除或重定义方法,会使得已创建的实例与新原型脱节,破坏内联缓存的有效性,也可能触发去优化(deoptimization)。
- 所有方法应在构造函数定义后立即一次性挂载到
prototype上,不要在模块加载后期或条件逻辑中补丁式添加 - 禁止使用
delete MyClass.prototype.method或MyClass.prototype.method = null - 若需“可选行为”,用配置参数或组合模式替代运行时原型篡改
优先使用类语法并明确继承层级
class 语法比传统函数+prototype 手动赋值更利于引擎静态分析。V8 对 extends 链有专门优化,但前提是继承关系稳定、无动态替换。
- 用
class A {}和class B extends A {}明确表达继承,避免B.prototype = Object.create(A.prototype)等手工操作 - 子类构造函数中必须调用
super(),且在调用前不访问this—— 违反会导致引擎放弃对该构造路径的优化 - 避免多层混用
class与函数式继承(如function C() {}继承自class B),易引发隐藏类不兼容
谨慎使用 Object.setPrototypeOf() 和 __proto__
这些 API 会直接篡改对象的原型引用,强制中断当前 IC 缓存,并可能使对象脱离快属性(fast properties)机制,退化为字典模式(dictionary mode)。
- 绝不在线上性能敏感路径中调用
Object.setPrototypeOf(obj, proto) - 避免在构造函数或热循环中读写
obj.__proto__ - 如需动态委托行为,改用组合(composition)或
Reflect.apply()显式调用目标方法


















