识别原型属性遮蔽需从代码结构和运行时行为两层面主动验证:用Object.hasOwn(obj,'prop')判断是否自有属性,用getOwnPropertyDescriptor查来源,观察构造函数中this赋值行为,并通过delete前后访问对比确认遮蔽。

识别原型属性遮蔽,关键不是等它出问题才察觉,而是从代码结构和运行时行为两个层面主动验证。遮蔽本身不报错,但会悄悄改变属性来源和共享逻辑。
看属性是否出现在对象自身上
用 Object.hasOwn(obj, 'prop')(推荐)或 obj.hasOwnProperty('prop') 检查:如果返回 true,说明该属性是实例自有属性,已遮蔽原型同名属性。
- 即使原型上已有
Person.prototype.name,只要执行了person.name = 'Alice',Object.hasOwn(person, 'name')就为 true -
in操作符无法区分——'name' in person对自有和继承属性都返回 true,不能用于识别遮蔽
查属性描述符,确认来源位置
调用 Object.getOwnPropertyDescriptor(obj, 'prop'):
- 若返回非 undefined,说明属性在
obj自身上,属于遮蔽行为 - 若返回 undefined,再用 Object.getOwnPropertyDescriptor(Object.getPrototypeOf(obj), 'prop') 查原型,就能确认它原本来自哪里
- 配合 Object.getOwnPropertyNames() 可列出所有自有属性,快速比对是否意外覆盖了原型方法(如
render、toString)
观察赋值动作与构造函数逻辑
遮蔽往往发生在初始化阶段,留意这些典型写法:
- 构造函数内直接
this.method = function() {...}—— 每个实例都会生成独立函数,遮蔽Constructor.prototype.method - 使用箭头函数赋值:
this.handleClick = () => {...}同样创建实例属性,且不可被super调用 - 手动设置同名配置:
this.timeout = 5000覆盖了Base.prototype.timeout的默认值,但未做类型/范围校验
运行时对比访问结果与删除后行为
最直接的验证方式:
- 先读取属性:
obj.prop→ 得到某个值 - 再执行
delete obj.prop - 再次读取:
obj.prop→ 如果值变了(比如从'custom'变成'default'),说明之前确实是遮蔽;如果仍报错或为undefined,说明原型上也不存在该属性











