遮蔽效应是属性查找时就近终止导致实例自有属性挡住原型同名属性:不修改/删除原型属性,仅截断查找路径;如p.name='alice'后仍保持person.prototype.name='unknown',object.hasown(p,'name')为true即表明遮蔽发生。

对象属性赋值时发生的“遮蔽效应”,本质是属性查找机制在遇到同名属性时的就近终止行为:只要实例自身拥有该属性,引擎就不再沿原型链向上查找,原 prototype 上的同名属性被“挡住”而不可见。
遮蔽不是覆盖,而是查找路径截断
遮蔽不修改原型上的属性,也不删除它,只是让访问逻辑停在实例层。比如:
- Person.prototype.name = 'Unknown' 定义了默认名
- const p = new Person(); p.name = 'Alice' 后,p.name 返回 'Alice',但 Person.prototype.name 仍是 'Unknown'
- 此时 Object.hasOwn(p, 'name') 为 true,说明遮蔽已发生
遮蔽常发生在初始化阶段
多数遮蔽并非有意为之,而是构造函数中直接赋值导致:
- this.render = function() {...} —— 每个实例都新建函数,遮蔽 prototype.render
- this.config = { timeout: 3000 } —— 即使父类 prototype 已定义 config,默认值无法复用
- 箭头函数赋值 this.handleClick = () => {...} 同样创建自有属性,且无法被 super 调用
遮蔽会破坏共享与一致性
本该由所有实例共用的属性或方法,一旦被实例属性遮蔽,就失去统一管理能力:
- 方法重复创建 → 内存占用上升,GC 压力增大
- 配置项各自独立 → 修改一处不影响其他实例,状态难以同步
- instanceof 或 isPrototypeOf 判断可能失真,例如手动重写 constructor 但未修正原型链
识别遮蔽的关键操作
不能依赖直觉,需用运行时工具确认:
- 用 Object.hasOwn(obj, 'prop') 判断是否为自有属性(推荐,比 hasOwnProperty 更可靠)
- 用 Object.getOwnPropertyDescriptor(obj, 'prop') 查描述符;若返回 undefined,再查原型链
- 执行 delete obj.prop 后再次访问,若值恢复为原型上的值,说明此前确为遮蔽











