最基础的类型检测工具——typeof, instanceof

typeofinstanceof 是 JavaScript 中两个最基础但也最容易让人困惑的类型检测工具。要深入理解它们的原理,我们需要从 JavaScript 的底层数据存储、类型系统和原型链机制入手。


typeof

typeof 是一个一元运算符,它的核心任务是返回一个代表操作数类型的字符串。其原理深入到 JavaScript 引擎是如何在底层存储和标识变量的。

1. 核心原理:底层类型标签(Type Tagging)

在 JavaScript 的早期实现中,值在引擎内部是由一个**类型标签(Type Tag)**和实际的数据值来表示的。这个类型标签存储在变量的机器码低位中,用于标识该值的类型。

  • 底层存储机制:JavaScript 引擎在存储变量时,会在内存中为变量分配空间,并用低位的1-3个比特位来存储其类型信息。
  • typeof 的工作方式 :当你对变量使用 typeof 操作符时,JavaScript 引擎并不会去回溯变量的创建过程,而是直接读取这个变量在内存中机器码低位的类型标签,然后将其映射为对应的类型字符串返回。

2. 机器码的类型映射

不同的类型对应着不同的低位标识。一个常见的类型标签映射如下:

  • 000 :对象(object)。
  • 010 :浮点数(number)。
  • 100 :字符串(string)。
  • 110 :布尔值(boolean)。
  • 1 :整数(number),整数类型标签是1,但会被归为 number 类型。
  • -2^30undefined

3. 著名的历史遗留问题:typeof null === 'object'

这是 JavaScript 中最著名的Bug之一,至今未被修复以保持兼容性。

  • 原因 :如前所述,对象的类型标签是 000。而**null 在底层表示的是空指针,在大多数实现中,空指针的机器码全是 0**。因此,当 typeof 读取 null 的类型标签时,发现是 000,就错误地将其判断为 object

4. 特例:函数的识别

虽然函数在底层也是对象(类型标签是 000),但 typeof function(){} 返回的是 'function'。这是因为 JavaScript 引擎内部对可调用对象做了特殊处理。当 typeof 操作符检测到一个对象内部实现了 [[Call]] 方法时,它会特殊处理并返回 "function"


instanceof

instanceof 是一个二元运算符,用于检测一个对象 的原型链上是否存在另一个构造函数prototype 对象。它的核心是原型链查找

1. 核心原理:原型链检查

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。其内部机制可以简单地用以下代码模拟:

javascript 复制代码
function myInstanceof(instanceObj, constructorFunc) {
    // 1. 获取实例对象的隐式原型(内部 [[Prototype]] 属性)
    let proto = Object.getPrototypeOf(instanceObj);

    // 2. 获取构造函数的显式原型
    let prototype = constructorFunc.prototype;

    // 3. 沿着原型链向上查找
    while (true) {
        // 4. 如果找到头(null)还没找到,返回 false
        if (proto === null) {
            return false;
        }
        // 5. 如果找到了匹配的原型,返回 true
        if (proto === prototype) {
            return true;
        }
        // 6. 继续向上一级查找
        proto = Object.getPrototypeOf(proto);
    }
}

2. 工作步骤详解

假设我们执行 obj instanceof Constructor,引擎会执行以下步骤:

  1. 获取隐式原型 :获取左侧对象 obj 的内部 [[Prototype]] 属性(在浏览器中可以通过非标准 __proto__ 或标准 Object.getPrototypeOf() 访问)。
  2. 获取显式原型 :获取右侧构造函数 Constructorprototype 属性。
  3. 循环比较 :将 obj 的隐式原型与 Constructor 的显式原型进行比较。
    • 如果相等,返回 true
    • 如果不相等,则将 obj 的隐式原型的隐式原型(即原型链的上一级)取出来,再次与 Constructor.prototype 比较。
    • 这个过程持续进行,直到原型链的末端(即 null)。如果一直没找到相等的对象,则返回 false

3. 重要特征

  • 跨窗口问题instanceof 依赖于原型链,因此它不能跨不同的全局执行环境 (例如,来自 iframe 的数组在父页面中使用 array instanceof parentWindow.Array 会返回 false),因为它们的原型链指向的是不同的 Array.prototype 对象。
  • 只能用于对象 :由于 instanceof 的机制是查找原型链,对于原始类型(string, number, boolean 等),它们不是对象,没有原型链,因此直接用 instanceof 检测原始类型会始终返回 false

总结对比

特征 typeof instanceof
本质原理 读取变量机器码低位的类型标签 遍历左侧对象的原型链 ,查找右侧构造函数的 prototype
返回值 字符串(如 "string", "object", "function" 布尔值(true / false
适用场景 检测原始类型 (除 null 外)和函数。 检测对象类型及其继承关系。
局限性 null 返回 "object";数组、日期等对象均返回 "object",无法细分。 不能跨窗口(iframe)使用;不能用于检测原始类型。
相关推荐
胡萝卜术9 小时前
力扣5. 最长回文子串
前端·javascript·面试
我星期八休息9 小时前
网络编程—应用层HTTP协议
linux·运维·开发语言·前端·网络·网络协议·http
不好听6139 小时前
前端路由完全指南(下篇):懒加载、History 栈与工程化实践
前端·react.js
触底反弹11 小时前
🔥 从零搭建 RAG 知识库:爬虫→分词→向量化→检索,一步都不能错
javascript·人工智能·面试
圣光SG11 小时前
Java Web入门基础知识笔记
java·前端·笔记
cyforkk12 小时前
Vercel 绑定自定义域名极简配置指南
服务器·前端·网络
এ慕ོ冬℘゜13 小时前
JavaScript 数组核心方法实战|新增元素 + 数组转字符串 零基础详解
开发语言·javascript·ecmascript
IT_陈寒14 小时前
React useEffect依赖数组中埋的坑,这次终于让我逮到了
前端·人工智能·后端
FourAu14 小时前
2026 前端突围指南:从 ESR 边缘渲染到封装 Web AI SDK,聊聊 AI 时代的职业进化
前端·人工智能