JavaScript 如何准确判断数据类型?5 种方法深度对比

在写js的时候,很容易因为数据类型没判断好而出错,比如这样的代码:

javascript 复制代码
function calculate(a, b) {
    return a + b;
}
// 我以为是 10 + 20 = 30
calculate(10, 20); // 结果 30 对的 

// 实际上用户输入的是字符串和数字
calculate("10", 20); // 结果为 "1020" 

所以为了避免这种情况的出现,我们还是要去判断好数据类型。

JavaScript中,有几种方式来判断数据类型,以下是常用的方法:

1. typeof 操作符

最常用的类型判断方法,但有一些局限性:

javascript 复制代码
typeof 42;           // "number"
typeof "hello";      // "string"
typeof true;         // "boolean"
typeof undefined;    // "undefined"
typeof null;         // "object" (历史遗留问题)
typeof {};           // "object"
typeof [];           // "object"
typeof function(){}; // "function"
typeof Symbol();     // "symbol"
typeof 42n;          // "bigint"

局限性

  • 无法区分数组、对象和 null
  • 函数返回 function
  • typeof 适合判断基本类型,但遇到对象类型就力不从心了

2. instanceof 操作符

用于检测构造函数的 prototype 属性是否出现在对象的原型链中:

javascript 复制代码
[] instanceof Array;           // true
{} instanceof Object;          // true
new Date() instanceof Date;    // true
function(){} instanceof Function; // true

// 继承关系,数组也是对象
[] instanceof Object;          // true

instanceof 的局限性:

javascript 复制代码
// 基本类型用不了
42 instanceof Number;          // false
"hello" instanceof String;     // false

在跨 iframe 或不同 window 环境下可能失效(因为构造函数不同)


3. Object.prototype .toString.call()

这是最准确、最可靠的方法,能识别所有内置类型!

javascript 复制代码
Object.prototype.toString.call(42);           // "[object Number]"
Object.prototype.toString.call("hello");      // "[object String]"
Object.prototype.toString.call(true);         // "[object Boolean]"
Object.prototype.toString.call(null);         // "[object Null]"
Object.prototype.toString.call(undefined);    // "[object Undefined]"
Object.prototype.toString.call([]);           // "[object Array]"
Object.prototype.toString.call({});           // "[object Object]"
Object.prototype.toString.call(function(){}); // "[object Function]"
Object.prototype.toString.call(Symbol());     // "[object Symbol]"
Object.prototype.toString.call(42n);          // "[object BigInt]"

我们封装一个实用的工具函数:

javascript 复制代码
function getRealType(value) {
    return Object.prototype.toString.call(value)
        .slice(8, -1)          // 截取"[object "和"]"之间的内容
        .toLowerCase();         // 转为小写,更友好
}

console.log(getRealType([]));        // "array"
console.log(getRealType(null));      // "null"
console.log(getRealType({}));        // "object"
console.log(getRealType(new Date())); // "date"

4. 专用方法

对于一些特殊类型,JavaScript提供了专门的判断方法:

判断数组:Array.isArray()

javascript 复制代码
Array.isArray([]);     // true
Array.isArray({});     // false
Array.isArray("123");  // false

判断NaN:Number.isNaN()

javascript 复制代码
// 注意区别!
isNaN("hello");        // true  ← 字符串不是数字,但这样判断容易误解
Number.isNaN("hello"); // false ← 更准确:只有真正的NaN才返回true
Number.isNaN(NaN);     // true

判断有限数字:Number.isFinite()

javascript 复制代码
Number.isFinite(42);     // true
Number.isFinite(Infinity); // false  ← 无穷大不是有限数字
Number.isFinite("42");   // false  ← 字符串不是数字

编写健壮的函数

在实际开发中的应用:

场景1:安全的数字相加

javascript 复制代码
function safeAdd(a, b) {
    // 确保两个参数都是数字类型
    if (typeof a !== 'number' || typeof b !== 'number') {
        throw new Error('参数必须是数字');
    }
    return a + b;
}

safeAdd(1, 2);     // 3
safeAdd(1, "2");   // 报错:参数必须是数字

场景2:处理多种数据类型

javascript 复制代码
function processData(data) {
    // getRealType方法在第3点Object.prototype.toString.call()中有写
    const type = getRealType(data); 
    
    switch(type) {
        case 'array':
            return data.map(item => item * 2);
        case 'object':
            return Object.keys(data).length;
        case 'string':
            return data.toUpperCase();
        case 'number':
            return data * 2;
        default:
            return '不支持的数据类型';
    }
}

console.log(processData([1, 2, 3]));    // [2, 4, 6]
console.log(processData("hello"));      // "HELLO"
console.log(processData({a: 1, b: 2})); // 2

总结:选择合适的方法

场景 推荐方法 示例
判断基本类型 typeof typeof "hello" === "string"
判断数组 Array.isArray() Array.isArray([])
判断自定义对象 instanceof obj instanceof MyClass
精确类型判断 Object.prototype.toString.call() 见上文工具函数
特殊值判断 专用方法 Number.isNaN(), Number.isFinite()

本文首发于公众号:程序员大华,专注分享前后端开发的实战笔记。关注我,少走弯路,一起进步!

📌往期精彩

写前端久了,我用 Node.js 给自己造了几个省力小工具

我也是写了很久 TypeScript,才意识到这些写法不对

ThreadLocal 在实际项目中的 6 大用法,原来可以这么简单

重构了20个SpringBoot项目后,总结出这套稳定高效的架构设计

相关推荐
用户908324602734 分钟前
Spring AI + RAG + SSE 实现带搜索来源的智能问答完整方案
前端·后端
GISer_Jing8 分钟前
阿里开源纯前端浏览器自动化 PageAgent,[特殊字符] 浏览器自动化变天啦?
前端·人工智能·自动化·aigc·交互
清风徐来QCQ27 分钟前
js中的模板字符串
开发语言·前端·javascript
成都渲染101云渲染666632 分钟前
Houdini+Blender高效渲染方案(高配算力+全渲染器兼容)
前端·系统架构
SuperEugene1 小时前
Vue3 + Element Plus 表格实战:批量操作、行内编辑、跨页选中逻辑统一|表单与表格规范篇
开发语言·前端·javascript
极梦网络无忧1 小时前
基于 Vite + Vue3 的组件自动注册功能
前端·javascript·vue.js
Predestination王瀞潞1 小时前
5.4.3 通信->WWW万维网内容访问标准(W3C):WWW(World Wide Web) 协议架构(分层)
前端·网络·网络协议·架构·www
爱学习的程序媛2 小时前
【Web前端】优化Core Web Vitals提升用户体验
前端·ui·web·ux·用户体验
zabr2 小时前
花了 100+ 篇笔记,我整理出 了一套 AI Agent 工程完全指南
前端·后端·agent
软弹2 小时前
深入理解 React Ref 机制:useRef 与 forwardRef 的协作原理
前端·javascript·react.js