属性遮蔽指对象自身属性优先于原型链同名属性被访问,读写均作用于自身,本质是属性查找顺序导致的覆盖感;验证遮蔽应使用hasownproperty而非in或undefined判断。

属性遮蔽(Property Shadowing)是理解 JavaScript 原型机制最直观的切入点:当对象自身拥有某个属性,而其原型链上也存在同名属性时,对象自身的属性会“挡住”原型上的那个,读写操作都只作用于自身——这并非删除或修改原型,而是查找时的优先级短路。
遮蔽的本质是查找顺序决定的覆盖感
JavaScript 属性访问始终遵循“先查自身,再沿 [[Prototype]] 向上找”的规则。所谓“覆盖”,其实是引擎在第一步就停下了,根本没机会走到原型上去。
- 读取
obj.x:如果obj自身有x,直接返回;否则才去obj.__proto__.x、obj.__proto__.__proto__.x…… 逐层找 - 赋值
obj.x = val:默认只设置在obj自身,哪怕原型上有个可写的x,它也不会被改写 - 删除
delete obj.x:只删自身属性;删完后再次读obj.x,就会自然落到原型链上,显现出“恢复继承”的效果
遮蔽发生在数据属性和方法上逻辑一致
函数在 JS 中只是普通属性,方法继承与数据属性继承共享同一套遮蔽机制。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 父类原型定义
say() { console.log('parent') } - 子实例
obj.say = function() { console.log('own') }→ 立即遮蔽,调用走自身版本 - 子构造函数原型上重写
Child.prototype.say = …→ 所有该类实例后续调用都走新方法(因实例自身无say,查找落到子原型)
访问器属性(getter/setter)需特别注意
若原型上用 Object.defineProperty 定义了 get x(),直接 obj.x = val 不会遮蔽它,反而可能触发原型的 setter;要真正遮蔽,必须也在自身重新定义访问器。
- ❌ 错误:
obj.x = 123—— 可能调用原型 setter,或静默失败(取决于原型 setter 行为) - ✅ 正确:
Object.defineProperty(obj, 'x', { get() { return 'shadowed' } }) - ✅ 更推荐:
class Child extends Parent { get x() { return 'child' } }
如何验证一个属性是否被遮蔽
靠 hasOwnProperty 最可靠,它只看“是不是我生的”,不关心原型有没有同名项。
-
obj.hasOwnProperty('x')返回true→ 自身有,无论原型有没有,都算遮蔽 -
'x' in obj返回true但obj.hasOwnProperty('x')是false→ 纯继承,未遮蔽 - 慎用
obj.x !== undefined:可能误判(原型属性值恰好是undefined)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










