对象实例的同名属性会遮蔽原型属性,而非覆盖;赋值即在实例上新建属性,不影响原型和其他实例;可用hasOwnProperty()和in操作符判断属性来源;删除实例属性可恢复访问原型属性。

对象实例的同名属性会自动屏蔽原型上的属性,这是 JavaScript 原型机制中默认且不可绕过的访问规则——不是“覆盖”,而是“遮蔽”(Property Shadowing)。
遮蔽发生的时机
只要你在实例上通过赋值方式设置一个与原型同名的属性,该属性就会立即出现在实例自身,后续访问时引擎不再沿原型链向上查找:
- 例如:
obj.name = "Alice",即使obj.__proto__.name存在,obj.name也只读取实例自身的值 - 这个过程不修改原型,也不影响其他实例,仅作用于当前对象
- 即使原型属性是只读的(
writable: false),赋值仍会在实例上新建属性并完成遮蔽
如何判断是否发生了遮蔽
用两个标准方法区分属性来源:
-
obj.hasOwnProperty("prop")返回 true → 属性在实例自身(已遮蔽) -
"prop" in obj返回 true → 属性可在实例或原型链上被访问(遮蔽或未遮蔽都成立) - 配合使用可明确:若
hasOwnProperty为 false 但in为 true,说明属性来自原型,尚未被遮蔽
遮蔽后如何恢复访问原型属性
只需删除实例上的同名属性,引擎会自然回落到原型链查找:
立即学习“Java免费学习笔记(深入)”;
-
delete obj.prop后,obj.prop就会重新读取原型上的值 - 注意:
delete只对实例属性有效;对原型属性使用delete会影响所有实例,应避免 - 若原型属性被定义为
configurable: false,则无法通过delete删除,此时遮蔽是单向的
常见误解澄清
遮蔽不是“覆盖原型”,也不是“继承失效”:
- 原型上的属性依然存在,其他实例照常访问
- 新增实例不会自动继承已被遮蔽的属性,它们仍从原型获取初始值
- 函数、数组等内置类型同样遵循此规则,比如给数组实例添加
length属性会遮蔽原型上的length访问器


















