javascript属性查找优先级为:先查实例自身,再沿原型链向上查找;实例属性会遮蔽原型同名属性,删除后恢复原型链查找,原型链查找严格单向线性,方法与数据属性规则一致,静态方法查function.prototype链。

是的,JavaScript 中属性查找的优先级就是:先查实例自身,再沿原型链向上查找。这个顺序是硬性规则,不因调用方式、this 指向或定义位置而改变。
实例属性永远最先被访问
只要对象自身(即 this 或实例)拥有该属性,无论原型链上同名属性是否存在、是否可写、是否是 getter,都会被直接返回——这叫“遮蔽”(shadowing)。
-
例如:
const p = new Person(); p.name = 'Alice'; Person.prototype.name = 'unknown'; console.log(p.name)输出'Alice' - 删除后恢复查找:
delete p.name;再次访问p.name就会落到Person.prototype.name - 类字段(
value = 123)和构造函数中this.xxx =都属于实例属性,天然享有最高优先级
原型链查找是单向、线性的
引擎不会跳过某一级,也不会并行搜索多个原型;它严格按 obj.__proto__ → __proto__.__proto__ → ... → Object.prototype → null 的路径逐级比对。
- 每一步只检查当前对象是否自有该属性(
hasOwnProperty级别),不关心是否可枚举、是否是 setter - 哪怕
Object.prototype.toString是只读方法,只要实例没定义自己的toString,就一定会走到这里 - 自定义继承(如
Child.prototype = Object.create(Parent.prototype))也必须保持这条链完整,否则中断即停止
方法和数据属性遵循同一套规则
函数在 JS 中就是普通属性值,obj.method() 的执行过程 = 先按原型链找到 method 这个函数引用,再以 obj 为 this 调用它。
- 所以
Array.prototype.map能被所有数组实例使用,是因为每个数组的__proto__都指向Array.prototype - 如果给某个数组实例加了
arr.map = customMap,那只有它自己走实例路径,其他数组不受影响 - 静态方法(
class A { static foo() {} })不参与此链,它查的是A.__proto__链(即Function.prototype)
注意遮蔽不等于删除
给实例赋同名属性只是盖住了原型上的那个,并不会修改或删除原型本身。这对调试和设计模式(如懒加载、默认配置覆盖)很关键。
- 可用
Object.getPrototypeOf(obj).hasOwnProperty('prop')显式检查原型是否真有该属性 -
in操作符会返回 true(因为包含继承属性),但hasOwnProperty只认实例自身 - 用
Object.defineProperty设置不可写/不可配置属性时,遮蔽行为仍生效,但后续赋值可能静默失败或抛错(取决于严格模式)











