JS-深度起底JS类型判断:typeof、instanceof 与 toString

前言

在 JavaScript 的世界里,准确判断一个变量的类型并不像看上去那么简单。为什么 typeof nullobject?为什么 instanceof 不能判断基本类型?本文将带你通过底层逻辑彻底搞定这些面试重难点。

一、 typeof:快速但有"缺陷"的选择

typeof 是最常用的判断方式,它直接返回一个表示类型的字符串。

1. 判断表现

  • 基本类型 :除了 null 之外,都能显示正确结果(string, number, boolean, undefined, symbol, bigint)。

  • 引用类型

    • 函数 :返回 "function"
    • 其他(数组、正则、日期、普通对象) :统一返回 "object"

2. 这里的坑:为什么 typeof null === 'object'?

底层原理: JavaScript 的底层变量是使用二进制存储的。为了提高性能,引擎通过二进制的前三位(Type Tag)来判断类型:

  • 000:对象(Object)
  • 1:整数
  • 010:浮点数
  • 100:字符串
  • 110:布尔值

null 的所有二进制位都是 0 ,因此它的前三位也是 000。早期的 JS 实现中没有对 null 进行特判,导致它被误判为了对象。这是一个历史遗留的 Bug,但为了兼容性一直没有修复。


二、 instanceof:基于原型链的"探亲"

instanceof 可以判断对象是属于哪种类型,它的内部机制是通过判断对象的原型链中是不是能找到该类型的 prototype.

1. 查找机制

只要右边变量的 prototype 在左边变量的原型链上就会返回ture,因此instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果原型链遍历完都没有找到,就会返回 false,告诉我们左边变量并不是右边变量的实例

2. 手写实现(面试常考)

手写 instanceof 的核心在于循环向上遍历原型链

JavaScript

javascript 复制代码
/**
 * 手写 instanceof 实现
 * @param {any} left 实例对象
 * @param {Function} right 构造函数
 */
function myInstanceof(left, right) {
    // 1. 基础判断:instanceof 左侧必须是对象或函数,且不能是 null
    if (!['function', 'object'].includes(typeof left) || left === null) {
        return false;
    }

    // 2. 获取右侧的显式原型
    let prototype = right.prototype;
    // 3. 获取左侧的隐式原型
    let proto = Object.getPrototypeOf(left); // 推荐使用此标准方法代替 __proto__

    while (true) {
        if (proto === null) return false; // 找到原型链尽头也没找到
        if (proto === prototype) return true; // 找到了
        proto = Object.getPrototypeOf(proto); // 继续向上查找
    }
}

三、 终极方案:Object.prototype.toString

如果你需要一个万能精准的判断方式,那么非它莫属。

1. 原理

调用该方法会返回一个格式为 [object Type] 的字符串,其中 Type 就是该值的内部属性 [[Class]]

2. 测试表现

JavaScript

javascript 复制代码
const toString = Object.prototype.toString;

console.log(toString.call(Math));      // [object Math]
console.log(toString.call('a'));       // [object String]
console.log(toString.call(null));      // [object Null]
console.log(toString.call(undefined)); // [object Undefined]
console.log(toString.call([]));        // [object Array]
console.log(toString.call(new Date())); // [object Date]

四、 面试模拟题(实战演练)

Q1:如何判断一个变量是否是数组?

参考回答:

  1. Array.isArray(arr)(首选,ES6标准方法)。
  2. Object.prototype.toString.call(arr) === '[object Array]'(最通用)。
  3. arr instanceof Array(注意:如果是在跨 iframe 环境下,原型链不同可能会失效)。

Q2:typeof []typeof {} 的结果分别是什么?

参考回答: 都是 "object"。因为 typeof 除了函数以外,对于所有的引用类型都会返回 "object"

Q3:执行 2 instanceof Number 的结果是什么?为什么?

参考回答: 结果是 false 。 因为 instanceof 只能用于检测对象实例。数字 2 是原始值(Primitive),它没有原型链。如果想让它返回 true,需要写成 new Number(2) instanceof Number

总结

  • typeof:适合判断基本类型(除 null)和函数。
  • instanceof:适合判断对象之间的继承关系。
  • toString:适合需要百分百准确判断类型的场景。
相关推荐
一位搞嵌入式的 genius9 分钟前
从 URL 到渲染:JavaScript 性能优化全链路指南
开发语言·前端·javascript·性能优化
芭拉拉小魔仙9 分钟前
Vue 3 组合式 API 详解:告别 Mixins,拥抱函数式编程
前端·javascript·vue.js
别叫我->学废了->lol在线等10 分钟前
taiwindcss的一些用法
前端·javascript
前端摸鱼匠35 分钟前
Vue 3 的ref在响应式对象中:介绍ref在reactive对象中的自动解包
前端·javascript·vue.js·前端框架·ecmascript
Polaris_YJH39 分钟前
使用Vue3+Vite+Pinia+elementUI搭建初级企业级项目
前端·javascript·elementui·vue
Highcharts.js42 分钟前
如何在构建音频图表中映射到数据?
javascript·信息可视化·音视频·开发文档·highcharts·数据映射
Jiaberrr43 分钟前
小程序setData性能优化指南:避开坑点,让页面丝滑如飞
前端·javascript·vue.js·性能优化·小程序
yuezhilangniao11 小时前
AI智能体全栈开发工程化规范 备忘 ~ fastAPI+Next.js
javascript·人工智能·fastapi
铅笔侠_小龙虾12 小时前
Flutter Demo
开发语言·javascript·flutter
2501_9445255412 小时前
Flutter for OpenHarmony 个人理财管理App实战 - 账户详情页面
android·java·开发语言·前端·javascript·flutter