属性屏蔽发生在对象自身添加与原型链同名属性时,该属性覆盖原型属性,使后续访问直接返回自身值;其触发条件为赋值操作且原型同名属性可写,或通过object.defineproperty显式定义;不当使用会破坏隐藏类一致性、退化属性存储模式、干扰内联缓存,从而引发隐性性能开销。

属性屏蔽本身不直接消耗性能,但不当使用会引发隐性开销——比如频繁触发原型链查找、意外创建冗余属性、或干扰引擎的优化路径。
属性屏蔽是怎么发生的
当对象自身添加一个与原型链上同名的属性时,这个新属性就“盖住”了原型上的那个。后续访问该属性,引擎不再向上查找,直接返回对象自身的值。
- 屏蔽只发生在赋值操作(
obj.x = val)且原型上存在同名可写属性时 - 如果原型属性是
writable: false,严格模式下报错,非严格模式下静默失败,不会屏蔽 - 用
Object.defineProperty显式定义自身属性,也会触发屏蔽,无论原型是否有同名属性
为什么屏蔽可能影响性能
看似只是“多存一个值”,但实际会影响 JavaScript 引擎(如 V8)的内联缓存(IC)和隐藏类(Hidden Class)机制:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 同一构造函数创建的对象,若有的被屏蔽、有的没被屏蔽,它们会分属不同隐藏类,导致方法无法被高效内联
- 反复增删屏蔽属性(如
obj.x = 1; delete obj.x)会让对象从“快属性”退化为“慢属性”,访问变慢 - for…in 或
in操作符仍会遍历原型链,但屏蔽后hasOwnProperty结果变化,可能让逻辑分支更难预测
怎么写更利于性能
不是避免屏蔽,而是让屏蔽行为可预期、可收敛:
- 初始化阶段就明确哪些属性属于实例(在构造函数里赋值),避免运行时随意覆盖原型属性
- 需要动态设置的配置项,统一收口到一个对象属性里(如
obj.config = {x: 1}),不直接污染实例键名 - 读多写少的共享数据,优先放在原型上;写多的个体状态,一定在构造时挂到实例上
- 用
Object.seal()或Object.freeze()锁定实例结构后,引擎更容易做优化
屏蔽是原型链的自然行为,关键在控制它发生的时机和范围。引擎不讨厌屏蔽,讨厌的是不可预测的结构变化。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










