You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何对象原型链上部分对象的constructor.prototype不指向其[[prototype]]?

为什么anyObject.constructor.prototype不等于Object.getPrototypeOf(anyObject)?

背景

可用于打印原型链的源对象种类很多,比如:

  • [1, 2, 3] // 数组字面量
  • {a: 1} // 对象字面量
  • new Set() // 内置Set
  • new Promise(() => {}) // 内置Promise
  • function foo(){} // 作为对象的函数
  • window // DOM全局window对象

实际上任意对象都能作为原型链的源对象。

我原本以为下面这个表达式永远成立:

anyObject.constructor.prototype === Object.getPrototypeOf(anyObject)

用这段代码打印原型链及每个对象的constructor:

function chain(o) {
    while (o) {
        console.dir(o);

        let tip = '';
        if (o.constructor.prototype === Object.getPrototypeOf(o))
            tip = 'points to the next object on the chain, i.e. its [[prototype]].';

        else if (o.constructor.prototype === o)
            tip = 'points to the above object itself.';

        else tip = 'NEVER EXECUTED TO HERE';

        console.log('Its constructor:', o.constructor, tip)
        o = Object.getPrototypeOf(o);
    }
}

但实际运行后发现,原型链上不是所有对象都符合这个预期,该怎么理解这种设计逻辑?


核心原因:constructor是可修改的普通属性,[[Prototype]]是对象的内置关联

1. 多数场景下的一致性

大多数普通对象确实符合你的预期:

  • 比如const arr = [1,2,3],arr.constructor指向Array构造函数,Array.prototype就是arr的内置原型([[Prototype]]),所以等式成立。
  • 普通字面量对象{a:1}同理,constructor指向Object,Object.prototype就是它的原型。

2. 打破一致性的典型场景

(1)原型链的终点:Object.prototype

Object.prototype是所有普通对象原型链的顶端,它的[[Prototype]]是null。但它的constructor指向Object构造函数,而Object.prototype正好是Object的prototype属性值——所以Object.prototype.constructor.prototype就是它自己,不等于null,这时就会触发你代码里的第二个分支。

这是JS语言的基础设计:Object.prototype没有上层原型,而它的构造函数Object的原型属性就是它本身。

(2)被修改过构造函数或原型的对象

如果手动修改了构造函数的prototype,或者直接修改对象的constructor属性,等式就会失效:

function Person() {}
const p = new Person();
// 替换构造函数的原型对象
Person.prototype = { name: 'test' };
// p的内置原型还是原来的Person.prototype,但p.constructor.prototype是新对象
console.log(p.constructor.prototype === Object.getPrototypeOf(p)); // false

因为p的constructor是继承自旧原型的constructor(指向Person),但Person的prototype已经被替换,两者自然不相等。

(3)宿主对象的特殊实现

像window这种浏览器宿主对象,它的原型链规则不一定完全遵循普通JS对象。比如window的constructor指向Window,但Window.prototype可能和window的内置原型不是同一个对象——这是浏览器厂商对全局对象的特殊设计。

另外像Array.prototype这种内置原型对象本身,它的constructor是Array,但它的内置原型是Object.prototype,所以Array.prototype.constructor.prototype(即Array.prototype)不等于Object.getPrototypeOf(Array.prototype)(即Object.prototype),也会触发第二个分支。

3. 设计逻辑的本质

  • constructor只是个可枚举、可修改的普通属性,本质是给对象打个“构造来源”的标签,但这个标签可以被随意修改,没有强制绑定关系。
  • [[Prototype]](通过Object.getPrototypeOf()访问)是对象的内置内部槽,是原型链查找的核心依据,它的关联在对象创建时就确定(除非用Object.setPrototypeOf()修改),是原型链的真实源头。

简单说:constructor是可撕可换的“标签”,[[Prototype]]才是对象真正的“原型父级”。


内容的提问来源于stack exchange,提问作者Zhang Wei

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 07:15:05