constructor中赋值的属性优先级最高,其次为类字段,最后为原型链上的同名属性;字段作为实例自有属性直接命中,遮蔽原型方法,访问遵循自身→原型链顺序。

constructor 里定义的属性,优先级高于类内部用 method() {} 这种语法定义的同名方法,也高于原型链上(包括父类 prototype)的同名属性或方法。但要注意:这里说的“类内部定义”,实际分两类——字段(field)和方法(method),它们在内存位置和查找机制上完全不同。
字段(如 name = "xxx")永远优先于同名原型方法
类中直接写的 name = "Alice" 是公共字段,等价于在 constructor 里写 this.name = "Alice"。它会作为实例自身的自有属性(own property)存在,访问时直接命中,根本不会去原型链查找。
- 哪怕你同时写了
getName() { return this.name; },只要实例上有getName = "string"字段,obj.getName就返回字符串,而不是调用函数 -
obj.hasOwnProperty("getName")返回 true,说明它确实在实例上 - 原型上的
getName()虽然存在,但被完全遮蔽,无法通过点号访问
constructor 中赋值的属性 > 类字段 > 原型属性
如果 constructor 显式设置了 this.name = "Bob",而类体里又声明了 name = "Alice",最终结果以 constructor 中的赋值为准——因为 constructor 执行在后,会覆盖字段的初始值。
- 字段初始化发生在 constructor 执行前(按规范顺序),但 constructor 内部的
this.xxx赋值会覆盖它 - 所以
constructor() { this.name = "Bob"; }+name = "Alice";→ 实例name是 "Bob" - 原型上的
name(比如Person.prototype.name = "Default")完全不会被读到,除非实例上没有该属性
方法定义不参与“同名覆盖”,只看属性存在位置
类中写的 getName() { ... } 是原型方法,它不会和实例上的字段冲突,而是根本不在同一层。JavaScript 属性访问是逐层查找:先实例自身 → 再 __proto__ → 再往上。字段和方法只是碰巧同名,但一个在实例上,一个在原型上。
- 不存在“方法覆盖字段”或“字段覆盖方法”的逻辑,只有“实例属性遮蔽原型属性”这一条规则
- 想让同名方法生效,就得确保实例上没有同名字段;反之,想用字段值,就别在原型上放同名方法干扰理解
- 调试时可用
console.dir(obj)看清属性在哪一层:自有属性标为“own”,原型方法在[[Prototype]]下
继承场景下的优先级链条很清晰
子类实例访问一个属性时,查找顺序固定:自身 → 子类 prototype → 父类 prototype → Object.prototype。constructor 和字段都落在“自身”这第一层。
- 哪怕父类 prototype 有
getName(),子类实例写了getName = 123,那就取 123 - 哪怕子类 constructor 没动
this.type,但父类 constructor 设置了,它仍属于实例自有属性 - 只有当所有层级都找不到时,才会得到 undefined

















