javascript属性访问严格遵循原型链查找:从实例自身开始,逐级向上至object.prototype,最终到null;实例属性优先遮蔽原型属性,方法与数据属性规则一致,getter/setter和object.defineproperty影响可枚举性与访问控制。

JavaScript 中属性访问优先级与继承链直接相关,但和 this 指向不同,它不依赖调用方式,而是严格遵循原型链(prototype chain)的查找顺序:从当前对象开始,逐级向上查找,直到找到属性或抵达 null。
属性查找走的是原型链,不是作用域链
每次访问一个对象的属性(如 obj.name),JS 引擎会:
- 先检查
obj自身是否拥有该属性(即在obj.hasOwnProperty('name')为true) - 如果没有,就去
obj.__proto__(即构造函数的prototype)上找 - 还没找到,继续查
__proto__.__proto__,依此类推 - 最终到
Object.prototype.__proto__ === null停止,返回undefined
实例属性优先于原型属性
即使原型上已定义同名属性,只要实例自身有该属性,就会被优先使用——这是“遮蔽”(shadowing)行为:
-
function Person(name) { this.name = name; }Person.prototype.name = 'unknown';const p = new Person('Alice');console.log(p.name); // 'Alice' —— 实例属性覆盖了原型上的 name - 删除实例属性后,原型属性才重新可见:
delete p.name;→ 再次访问p.name得到'unknown'
方法和数据属性遵循同一规则
函数也是属性,查找逻辑完全一致:
-
obj.toString()实际调用的是Object.prototype.toString(除非obj自己定义了toString) -
Array.prototype.map能被所有数组实例访问,是因为[].__proto__ === Array.prototype - 若子类重写父类方法(如在子类
prototype上定义同名函数),就自然覆盖父类原型上的版本
注意 get/set 访问器和 Object.defineProperty 的影响
通过 Object.defineProperty 设置的属性可控制是否可枚举、可配置、是否具有访问器,这些会影响查找行为:
- 不可枚举属性(
enumerable: false)仍能被正常访问,只是不会出现在for...in或Object.keys()中 - 如果某个原型上的属性是 getter,而实例上定义了同名数据属性,则实例属性优先;反之,若实例上也定义了 getter,它会完全接管访问
- 使用
Object.create(null)创建的对象没有原型,因此属性查找立即终止,不存在继承
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











