现代 JavaScript 引擎通过 IC 缓存和隐藏类使深层原型链访问接近自有属性速度,性能瓶颈主因是动态修改原型、不稳定链结构及高频访问属性未实例化;应冻结稳定原型、避免运行时改链、优先静态继承与组合模式。

原型链本身不是靠“缩短深度”来优化性能的,现代 JavaScript 引擎(如 V8)早已通过查找缓存(IC,Inline Caches)和隐藏类(Hidden Classes)机制,让深层原型链上的属性访问几乎与对象自身属性访问一样快。真正影响响应速度的,往往不是链长本身,而是不合理的链结构、频繁的动态修改或误用方式。
避免在运行时反复修改原型链
每次给 __proto__ 赋值、调用 Object.setPrototypeOf() 或使用 Object.create() 创建大量不同原型的对象,都会导致引擎放弃对相关对象的优化假设,触发去优化(deoptimization),使后续属性访问变慢。
- 不要在循环或高频函数中动态改写原型
- 优先用静态继承结构:构造函数 + prototype 定义,而非运行时拼接 __proto__ 链
- 若需多态行为,考虑组合模式或策略对象,而非深链继承
控制原型链长度,但不必追求“扁平”
虽然 V8 对 4–5 层的查找做了良好优化,但超过 10 层且每层都含大量自有属性时,仍可能增加首次查找开销(尤其冷启动阶段)。关键不是层数绝对值,而是链上对象是否“稳定”和“可预测”。
- 典型安全范围:pockets → bed → table → head(4 层)完全无压力
- 应警惕的是:A → B → C → D → E → F → G → … → Object.prototype(8+ 层)且中间多为临时对象
- 可用 Object.getPrototypeOf(obj) 检查实际链长,辅助定位异常长链
把高频访问属性尽量放在靠近实例的位置
即使引擎做了缓存,首次访问仍需遍历。对每秒调用成千上万次的属性(如渲染循环中的 x、y、visible),直接挂载到实例上比从原型链上取更稳妥。
- 例如:游戏实体的坐标、状态标志位,建议初始化时赋给 this
- 方法可保留在 prototype 上(共享复用),但简单数据字段优先实例化
- 避免 obj.x 每次都从第 4 层原型上读取,尤其当 x 是数值型且被频繁计算时
用 Object.freeze() 锁定稳定原型对象
冻结原型对象(如 Person.prototype、EventEmitter.prototype)能帮助引擎确认其结构不会变化,从而启用更激进的内联缓存和类型推测,提升后续所有继承实例的属性访问效率。
- 注意:冻结只作用于对象自身属性,不影响原型链向上查找
- 常见做法:
Object.freeze(Person.prototype);放在构造函数定义之后、首次实例化之前 - 配合 const 声明原型方法,进一步强化不可变语义


















