在学习 JavaScript 的过程中,你是否曾被以下现象困惑过?

typeof Object;   // "function"
typeof {};       // "object"

明明 Object 是“对象”的代表,为什么它自己却是个函数?
{} 才是我们日常使用的“对象”,却被识别为 "object"

更令人费解的是,ObjectFunction 之间还存在一种看似“循环引用”的原型关系:

Object.__proto__ === Function.prototype;   // true
Function.__proto__ === Function.prototype; // true

本文将带你彻底理清这两个问题背后的机制,揭开 JavaScript 原型系统的神秘面纱。


一、先回答:为什么 typeof Object ≠ typeof {}

✅ 核心原因:它们根本不是同一类东西!

表达式实际类型说明
Object内置构造函数(函数)可调用:Object() 或 new Object()
{}普通对象字面量不可调用,是 Object 的实例

根据 ECMAScript 规范,typeof可调用对象(即具有 [[Call]] 内部方法的对象)返回 "function",否则返回 "object"

所以:

  • Object 是一个函数 → typeof Object === "function"
  • {} 是一个普通对象 → typeof {} === "object"

💡 类比理解:

  • Object 是“造车的工厂”(函数)
  • {} 是“工厂生产出来的一辆车”(对象)

二、深入:Object 和 Function 的原型关系

要理解上述现象,必须搞懂 JavaScript 中最核心的两个内置对象:ObjectFunction

1. 基本事实

  • 所有函数(包括 ObjectArrayDate)都是 Function 的实例。
  • 所有普通对象(包括 {}[]Function.prototype)最终都继承自 Object.prototype

因此:

Object instanceof Function;   // true
Function instanceof Function; // true
({}).__proto__ === Object.prototype; // true

2. 它们的 __proto__ 指向哪里?

表达式说明
Object.__proto__Function.prototypeObject 是函数,由 Function 构造
Function.__proto__Function.prototypeFunction 自身也是函数
Function.prototype.__proto__Object.prototypeFunction.prototype 是普通对象
Object.prototype.__proto__null原型链终点

3. 原型关系图(文字版)

Function ──.__proto__──→ Function.prototype ──.__proto__──→ Object.prototype ──.__proto__──→ null
   ↑
   │ (instanceof)
Object ──.__proto__───────────────────────────────────────┘

🔁 这看起来像“鸡生蛋、蛋生鸡”,但实际上是 JS 引擎在初始化时预定义好的闭环结构


三、验证代码(建议在控制台运行)

// 1. typeof 差异
console.log(typeof Object); // "function"
console.log(typeof {});     // "object"

// 2. instanceof 验证
console.log(Object instanceof Function);   // true
console.log(Function instanceof Function); // true

// 3. __proto__ 关系
console.log(Object.__proto__ === Function.prototype);   // true
console.log(Function.__proto__ === Function.prototype); // true

// 4. Function.prototype 是普通对象
console.log(typeof Function.prototype); // "object"
console.log(Function.prototype.__proto__ === Object.prototype); // true

// 5. Object.prototype 是原型链顶端
console.log(Object.prototype.__proto__ === null); // true

四、常见误区澄清

误区1:Object 是最顶层对象,所以 Object.__proto__ 应该是 null

✅ 正解:Object函数,不是普通对象。所有函数的 __proto__ 都指向 Function.prototype

误区2:Function.prototype 是一个函数

✅ 正解:typeof Function.prototype 返回 "object",它是一个内置的普通对象,仅用于被函数实例继承。

误区3:{} 和 Object 是等价的,所以 typeof 应该一样

✅ 正解:{}Object实例,就像 new Array()Array 的关系一样——构造函数 vs 实例


五、延伸:如何正确判断类型?

由于 typeof 对对象一律返回 "object"(连 null 也是!),我们常使用:

Object.prototype.toString.call(value).slice(8, -1)

例如:

Object.prototype.toString.call([])           // "[object Array]"
Object.prototype.toString.call(new Date())   // "[object Date]"
Object.prototype.toString.call(/regex/)      // "[object RegExp]"
Object.prototype.toString.call(null)         // "[object Null]"
Object.prototype.toString.call(undefined)    // "[object Undefined]"
Object.prototype.toString.call(123)          // "[object Number]"
Object.prototype.toString.call("str")        // "[object String]"
Object.prototype.toString.call(true)         // "[object Boolean]"
Object.prototype.toString.call(Symbol())     // "[object Symbol]"
Object.prototype.toString.call(() => {})     // "[object Function]"
Object.prototype.toString.call({})           // "[object Object]"

这正是利用了 Object.prototype.toString 能返回内部 [[Class]] 标签的特性。


六、总结

问题答案
为什么 typeof Object 是 "function"因为 Object 是一个可调用的构造函数
为什么 typeof {} 是 "object"因为 {} 是一个普通对象实例
Object.__proto__ 指向哪?Function.prototype
Function.__proto__ 指向哪?Function.prototype
原型链终点是?Object.prototype.__proto__ === null

🌟 记住

  • 函数也是对象,但可调用 → typeof 返回 "function"
  • Object 是“模具”,{} 是“产品”
  • 整个原型系统由 Object 和 Function 共同构建

参考资料

  • ECMAScript® 2024 Language Specification
  • MDN: typeof
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐