JavaScript属性查找遵循“就近原则”:先查实例自身,再沿__proto__向上查原型及原型的原型,直至null;同名属性在实例上定义即遮蔽原型链上所有同名项。

当 JavaScript 对象实例访问某个属性时,如果该属性在实例自身不存在,引擎会沿着原型链向上查找——这个过程天然决定了“冲突”的本质不是错误,而是查找顺序的结果。关键不在于避免冲突,而在于理解谁先被找到、谁被忽略、以及如何有意识地控制它。
属性查找优先级:实例 > 原型 > 原型的原型
JavaScript 属性访问遵循“就近原则”:先查实例自身(this 或 obj 直接拥有的属性),再查 __proto__ 指向的原型对象,然后是原型的原型,直到 null。这意味着:
- 同名属性在实例上定义,就永远遮蔽原型链上所有同名项
-
my.z = 4后,即使My.prototype.z存在,my.z读取结果始终是4 - 遍历(如
for...in)默认包含可枚举的原型属性,需用hasOwnProperty过滤才只看实例自有属性
方法重名不是 bug,而是覆盖逻辑的自然体现
多层原型继承中出现同名方法(如 render),JS 不报错,而是按原型链顺序取第一个匹配项。是否构成问题,取决于你的设计意图:
- 想完全替换父行为?直接在子构造函数的
prototype上定义同名方法即可 - 想增强父逻辑(比如“校验后再提交”)?在子方法里用
Parent.prototype.methodName.call(this, ...)显式调用 - 想保留两个版本共存?改用语义化命名,如
initBasic和initWithAuth,避免强行复用同一名称
数据属性与访问器属性不能共存
ES5 规定:同一对象中,一个属性名不能同时拥有数据描述符(p: 5)和访问器描述符(get p())。对象字面量中若多次声明同名属性,后定义者会彻底覆盖前一个:
立即学习“Java免费学习笔记(深入)”;
-
{ p: 1, get p() { return 2; } }→ 最终只有 getter,读取p返回2 -
{ get p() { return 2; }, p: 1, set p(v) {} }→ 最终只有 setter,读取p返回undefined(不报错) - 安全做法:用私有字段(如
_p)存值,再通过独立的get p()/set p(v)控制访问
合并多个对象时的属性覆盖策略
使用 Object.assign() 或展开运算符合并对象时,后出现的对象同名属性会覆盖前面的。这不是原型链行为,但常被误认为“冲突”:
- 浅合并场景下,这是预期行为,无需干预
- 需要深度合并(如嵌套对象也要递归合并)?得手写逻辑或借助
lodash.merge - 想自定义冲突规则(例如数组拼接、数值相加、保留首次值)?必须遍历键并逐个判断类型与策略


















