JavaScript原型是对象内部的[[Prototype]]链接,决定属性查找路径;原型链继承通过子对象[[Prototype]]指向父构造函数prototype实现;直接修改constructor会导致实例constructor指向错误,需手动修复。

JavaScript 原型不是“类模板”,而是每个对象内部隐含的 [[Prototype]] 链接,它决定了属性和方法的查找路径;原型链继承的本质,是让子对象的 [[Prototype]] 指向父构造函数的 prototype 对象。
为什么直接改 constructor 会出问题?
当你用 Child.prototype = Object.create(Parent.prototype) 设置原型链后,Child.prototype.constructor 会变成 Parent,而不是 Child。这会导致 new Child() 实例的 constructor 指向错误,影响类型判断和实例重建逻辑。
- 修复方式:手动重设
Child.prototype.constructor = Child - 不修复的典型表现:
new Child().__proto__.constructor === Parent(应为Child) - 现代写法推荐用
class,但底层仍依赖这套机制——class的extends就是自动处理了constructor重绑定
Object.getPrototypeOf() 和 __proto__ 有什么区别?
__proto__ 是非标准但广泛支持的访问器属性,而 Object.getPrototypeOf() 是规范推荐的获取方式。两者都返回对象的 [[Prototype]],但行为细节不同:
-
__proto__可读可写,但修改它有性能代价,且在严格模式下对某些对象(如字面量对象)可能静默失败 -
Object.getPrototypeOf(obj)安全、标准、不可写,适用于所有环境 - 不要混用:
obj.__proto__ = null会切断原型链,但Object.setPrototypeOf(obj, null)才是等效的标准写法
为什么 hasOwnProperty() 不走原型链?
hasOwnProperty() 是 Object.prototype 上的方法,但它被设计为只检测对象**自身属性**,不沿 [[Prototype]] 向上查找——这是它和 in 操作符的根本区别。
立即学习“Java免费学习笔记(深入)”;
-
'x' in obj→ 查自身 + 整条原型链 -
obj.hasOwnProperty('x')→ 只查自身(哪怕x在原型上定义了也不命中) - 注意:如果对象自身覆盖了
hasOwnProperty(比如obj.hasOwnProperty = () => true),那它就失效了;稳妥写法是Object.prototype.hasOwnProperty.call(obj, 'x')
用 Object.create(null) 创建的对象没有原型链
这类对象的 [[Prototype]] 是 null,所以它既没有 toString(),也没有 hasOwnProperty(),甚至不能用 for...in 遍历(因为没继承 Object.prototype 的枚举逻辑)。
- 适用场景:纯哈希表(如缓存 map)、避免原型污染的配置对象
- 常见误用:把它当普通对象传给期望有原型方法的库(比如某些深拷贝函数会报
obj.toString is not a function) - 补救方式:若必须加方法,只能手动挂载,例如
obj.toString = () => '[object Map]',但无法恢复完整原型链
原型链真正难的不是怎么连,而是什么时候该断——比如深拷贝时要不要保留原型,事件委托中如何区分原生方法和自定义方法,还有 instanceof 在跨 iframe 场景下的失效问题。这些都不是靠记住规则能解决的,得看具体对象的 [[Prototype]] 是谁、在哪儿断的。











