Object.setPrototypeOf 不改变对象自身的 constructor 属性,仅影响原型链查找起点;constructor 是可配置的普通属性,非引擎强制维护,类型判断应优先使用 instanceof 或 Object.prototype.toString.call()。

调用 Object.setPrototypeOf 不会改变原对象的 constructor 属性值,也不会自动更新其内部的 [[Constructor]] 关联。构造函数本身(即 obj.constructor)只是普通属性,它是否变化,取决于你设置的新原型对象上有没有 constructor 属性,以及该属性的值是什么。
constructor 是个可配置的普通属性
constructor 并非 JavaScript 引擎强制维护的元属性,而是原型链上一个常规的、可读写的属性。比如:
function A() {}
const a = new A();
console.log(a.constructor === A); // true
这是因为 A.prototype.constructor 默认指向 A。但这个链接很容易被覆盖或丢失:
- 如果你把
a的原型设为一个没有constructor的空对象:Object.setPrototypeOf(a, {});→a.constructor会沿原型链向上找,最终落到Object.prototype.constructor,即Object - 如果你设为一个自定义原型:
const proto = { constructor: B }; Object.setPrototypeOf(a, proto);→a.constructor就变成B
setPrototypeOf 不影响对象自身的 constructor 属性
对象自身如果没有定义 constructor,访问它时总是从原型链上查找。所以 Object.setPrototypeOf 改变的是查找起点,而不是重写对象自己的 constructor。即使你之前手动在对象上设置了 a.constructor = C,这个自有属性依然保留,不会被原型变更覆盖。
安全做法:显式修复 constructor(如需)
如果希望语义清晰、避免误判类型,建议在更换原型后手动同步 constructor:
- 使用
Object.defineProperty设置不可枚举、不可配置的constructor(模仿原生行为):Object.defineProperty(newProto, 'constructor', { value: MyConstructor, writable: true, enumerable: false, configurable: true }); - 或简单赋值(适合开发调试):
newProto.constructor = MyConstructor; - 然后执行:
Object.setPrototypeOf(obj, newProto);
注意 instanceof 和 constructor 的区别
instanceof 检查的是原型链是否包含指定构造函数的 prototype,和 constructor 属性无关。哪怕你把 obj.constructor 改成 String,只要它的原型链里没出现 String.prototype,obj instanceof String 仍是 false。不要依赖 constructor 判断类型,应优先用 instanceof 或 Object.prototype.toString.call()。

















