JS中为何Object.getPrototypeOf(Function)===Function.prototype?
Function自举矛盾的本质解释 你之前总结的“实例由构造函数调用生成、时序上必然晚于构造器”,完全是运行时业务场景下的经验总结——这套规律只适用于开发者在代码执行阶段,手动通过new或直接调用构造函数生成的普通自定义对象,根本不适用于JS引擎在启动阶段就完成初始化的核心原生对象,二者的生成逻辑从根源上就不是一套流程。
先从规则本质拆解冲突点
你一开始记住的判定规则Object.getPrototypeOf(obj) === Constructor.prototype是完全准确的,这条规则的作用是描述原型继承的链路关系,从来没有附带过“这种关系必须靠手动调用构造函数、在业务代码运行阶段建立”的前提。
对于普通的自定义构造函数来说,这个链路确实是开发者先定义构造函数、为其挂载prototype属性,再通过调用new生成实例,引擎在实例上绑定指向Constructor.prototype的原型引用——这套流程里自然是构造器先存在、实例后生成。
但Function是引擎在全局环境刚加载完成、第一行业务代码还未执行时,就已经在内核中创建完成的原生对象,它的原型链路从创建那一刻就是直接内置绑定的,根本不需要走“调用构造器生成实例”的常规流程。
为什么Function必然满足“自身是自身实例”的规则
这不是JS设计时的随意选择,是原型系统为了满足“所有函数本质都是对象”的统一规则推导出的必然结果:
- JS中所有对象的属性查找链路,最终都会走到
Object.prototype,这是整个原型系统的公共终点 - JS中所有可以被调用、可以当构造器用的函数,本身也是对象,这些函数对象的属性查找链路,自然也需要最终走到
Object.prototype - 为了让所有函数的链路不重复建设,JS专门设计了公共的“函数原型”对象——也就是
Function.prototype:所有函数的内部原型引用([[Prototype]])都指向这个对象,再由Function.prototype向下连到Object.prototype,整个链路就通了。
顺着这个逻辑往下推就会得到必然结论:
- 所有内置构造器(
Object、Array、String等)、所有开发者自定义的普通函数,本质都是函数对象,它们的[[Prototype]]自然都指向Function.prototype Function本身也是个函数对象,它不例外,它的[[Prototype]]同样指向Function.prototype- 而
instanceof的判定逻辑,本质就是检查“构造函数的prototype属性是否存在于左侧对象的原型链上”,所以自然会得到Function instanceof Function === true的结果。
这里需要澄清一个最容易造成误解的点:很多人以为这个结果代表
Function是“通过调用自己生成自己”的,完全不是。它没有走任何“被生成”的流程,是引擎在内核里直接硬编码创建的特殊对象——从它被创建出来的第一秒,原型指向关系、作为构造器的能力就已经全部配置完成,不存在“先生成谁、再生成为谁”的循环时序问题。
直白梳理引擎初始化的实际流程
JS引擎启动时的内置对象构建,根本不是“构造器生成实例、实例再当构造器”的递归循环,就是顺次完成的静态配置,根本没有鸡生蛋的矛盾:
- 第一步,先创建原型链的最终终点
Object.prototype:这是一个普通空对象,它的内部原型指向null,不关联任何构造函数 - 第二步,创建公共的函数原型
Function.prototype:这是一个可调用的普通对象,它的内部原型指向第一步创建的Object.prototype - 第三步,创建
Function构造函数:这个函数的内部原型直接指向第二步的Function.prototype,同时它的prototype属性就是第二步创建的Function.prototype对象 - 后续所有内置构造器(
Object、Array、String、Number等),本质都是函数类型,它们的内部原型统一指向第二步的Function.prototype,各自的prototype属性再挂载到Object.prototype的下游
你之前感受到的时序矛盾,本质是把日常写代码时“手动调用构造器生成实例”的经验,硬套到了引擎启动阶段的内置对象初始化逻辑上——后者根本不需要走调用构造器的生成流程,自然不存在先后顺序的绑定问题。
内容的提问来源于stack exchange,提问作者wlnirvana

