JS对象属性查找沿原型链委托:先查自身属性,存在则直接返回,不查原型;未找到则沿[[Prototype]]向上查找直至null。读取走原型链,赋值默认写入自身。

JS 中对象属性查找走的是原型链,不是一层层“遍历”,而是沿着 __proto__(即内部的 [[Prototype]])向上逐级委托查找,直到找到属性或到达原型链顶端(null)为止。
查找从当前对象开始,不跳过自身
每次访问对象的属性(如 obj.x),引擎先检查该对象自身是否拥有这个属性(即是否在自己的属性键中,包括可枚举和不可枚举的自有属性)。如果存在,直接返回值,**不继续查原型**。
- 用
Object.hasOwn(obj, 'x')(或旧版obj.hasOwnProperty('x'))可判断是否为自有属性 - 即使原型上有同名属性,只要自身有,就屏蔽(shadow)原型上的那个
没找到时自动转向 [[Prototype]]
若自身没有该属性,JS 引擎会取当前对象的 [[Prototype]](也就是 obj.__proto__ 指向的对象),在它上面重复查找过程。这个过程会持续进行,形成一条链:
obj → obj.__proto__ → obj.__proto__.__proto__ → ... → null- 所有普通对象的终点是
Object.prototype,它的__proto__是null - 函数对象的原型链还经过
Function.prototype,再连到Object.prototype
方法调用本质也是属性查找
像 arr.push(1) 并不是“数组天生有 push”,而是:arr 自身没有 push,于是查 arr.__proto__(即 Array.prototype),在那里找到了 push 方法,然后以 arr 为 this 执行它。
- 所以
Array.prototype.push、Object.prototype.toString等都是挂在原型上的共享方法 - 修改原型(如
Array.prototype.myMap = ...)会影响所有数组实例(不推荐但可行)
注意几个关键细节
原型链查找只对“读取”(get)生效;赋值(set)默认写入当前对象,不会修改原型:
-
obj.x = 123总是在obj上添加/覆盖x,哪怕obj.__proto__.x存在 - 要真正修改原型上的属性,必须显式写到原型上,例如
obj.__proto__.x = 456 -
in操作符查整个原型链,hasOwnProperty只查自身,Object.keys()也只返回自身可枚举属性











