前端判断数据类型的所有方式详解

在 JavaScript 中,准确判断数据类型是开发的基础技能。由于 JS 的动态特性和历史遗留问题,判断类型的方法多种多样,且各有优劣。

以下是目前前端开发中常用的所有判断方式详解。

1. typeof 操作符

typeof 是最基础的判断方式,它可以直接返回一个表示数据类型的字符串。

适用场景 :判断基本数据类型(除了 null)。

语法

javascript 复制代码
typeof operand
// or
typeof(operand)

例子

javascript 复制代码
// 基本类型
console.log(typeof 123);           // "number"
console.log(typeof 'abc');         // "string"
console.log(typeof true);          // "boolean"
console.log(typeof undefined);     // "undefined"
console.log(typeof Symbol('id'));  // "symbol"
console.log(typeof 10n);           // "bigint"

// 引用类型
console.log(typeof function(){});  // "function" (特别注意:函数是唯一能被 typeof 区分出的引用类型)
console.log(typeof {});            // "object"
console.log(typeof []);            // "object" (无法区分数组和对象)
console.log(typeof new Date());    // "object"

⚠️ 局限性 (著名的 Bug)

typeof 最大的坑在于判断 null

javascript 复制代码
console.log(typeof null); // "object"

这是 JS 初期的设计错误,为了兼容性一直保留至今。因此 不能用 typeof 判断 null


2. instanceof 操作符

instanceof 用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

适用场景:判断引用类型(对象、数组、正则、日期等),判断自定义类的实例。

语法

javascript 复制代码
object instanceof constructor

例子

javascript 复制代码
const arr = [1, 2, 3];
const date = new Date();
const func = function() {};

console.log(arr instanceof Array);       // true
console.log(arr instanceof Object);      // true (数组也是对象)
console.log(date instanceof Date);       // true
console.log(func instanceof Function);   // true

// 自定义类
class Person {}
const p = new Person();
console.log(p instanceof Person);        // true

⚠️ 局限性

  1. 无法判断基本数据类型

    javascript 复制代码
    console.log(123 instanceof Number); // false
  2. 原型链被修改后失效

    javascript 复制代码
    function Foo() {}
    const f = new Foo();
    f.__proto__ = {}; // 修改原型指向
    console.log(f instanceof Foo); // false
  3. 跨 iframe/window 问题
    在多个 iframe 之间传递数组时,iframeA 的数组 instanceof iframeB.Array 会返回 false,因为环境不同,构造函数不同。


3. Object.prototype.toString.call() (推荐 🔥)

这是目前公认最准确、最通用 的类型判断方法。它利用了 Object 原型上的 toString 方法,返回格式为 [object Type] 的字符串。

适用场景:所有类型,包括基本类型和引用类型。

语法

javascript 复制代码
Object.prototype.toString.call(value)

例子

javascript 复制代码
// 基本类型
console.log(Object.prototype.toString.call(123));           // "[object Number]"
console.log(Object.prototype.toString.call('str'));         // "[object String]"
console.log(Object.prototype.toString.call(true));          // "[object Boolean]"
console.log(Object.prototype.toString.call(undefined));     // "[object Undefined]"
console.log(Object.prototype.toString.call(null));          // "[object Null]"

// 引用类型
console.log(Object.prototype.toString.call([]));            // "[object Array]"
console.log(Object.prototype.toString.call({}));            // "[object Object]"
console.log(Object.prototype.toString.call(new Date()));    // "[object Date]"
console.log(Object.prototype.toString.call(/regex/));       // "[object RegExp]"
console.log(Object.prototype.toString.call(function(){}));  // "[object Function]"
console.log(Object.prototype.toString.call(Math));          // "[object Math]"

封装通用工具函数

javascript 复制代码
function getType(value) {
  const type = Object.prototype.toString.call(value);
  // 截取 "[object Type]" 中的 "Type" 并转小写
  return type.slice(8, -1).toLowerCase();
}

console.log(getType([]));   // "array"
console.log(getType(null)); // "null"

4. constructor 属性

每个对象实例都有一个 constructor 属性,指向创建该实例的构造函数。

适用场景:判断引用类型,检查数据是由哪个构造函数生成的。

语法

javascript 复制代码
value.constructor === Constructor

例子

javascript 复制代码
const arr = [];
const num = 123;

console.log(arr.constructor === Array);   // true
console.log(arr.constructor === Object);  // false (这点比 instanceof 准确,不回溯原型链)

console.log(num.constructor === Number);  // true (数字字面量会自动包装)
console.log((1).constructor === Number);  // true

⚠️ 局限性

  1. nullundefined 没有 constructor ,访问会报错。

    javascript 复制代码
    // null.constructor // TypeError
  2. 不可靠 :如果手动修改了原型的 constructor 属性,判断就会出错。

    javascript 复制代码
    function A() {}
    A.prototype.constructor = Array; // 恶意修改
    const a = new A();
    console.log(a.constructor === Array); // true (实际类型是 A,判断错误)

5. 特定类型的判断方法

除了上述通用方法,JS 还提供了一些针对特定类型的静态方法。

5.1 Array.isArray()

ES5 新增,专门用于判断数组,解决了 instanceof 在跨 iframe 时的 Bug。

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

5.2 Number.isNaN()

判断一个值是否严格等于 NaN(Not-a-Number)。注意与全局 isNaN() 的区别。

javascript 复制代码
// 全局 isNaN 会尝试先转数字,再判断,容易误判
console.log(isNaN("abc"));        // true ("abc" 转数字是 NaN)

// Number.isNaN 不会进行类型转换,更严谨
console.log(Number.isNaN("abc")); // false
console.log(Number.isNaN(NaN));   // true

总结与对比

方法 适用范围 优点 缺点
typeof 基本数据类型 语法简单,性能高 无法区分 Object、Array、Null
instanceof 引用类型 能检测继承关系 无法检测基本类型,原型可被修改
Object.prototype.toString 所有类型 最准确,无死角 语法稍显繁琐
constructor 大部分类型 简单直接 不安全(可被修改),不支持 null/undefined
Array.isArray 仅数组 官方标准,解决 iframe 问题 仅限数组

最佳实践代码

在实际项目中,建议使用以下组合策略:

javascript 复制代码
function getDataType(data) {
  // 1. 优先处理 null
  if (data === null) return 'null';
  
  // 2. 处理 undefined (typeof undefined 是安全的)
  if (typeof data === 'undefined') return 'undefined';
  
  // 3. 处理基本类型 (除了 null)
  if (typeof data !== 'object' && typeof data !== 'function') {
    return typeof data;
  }
  
  // 4. 使用 toString 处理引用类型 (Array, Date, RegExp, Object, Error 等)
  const tag = Object.prototype.toString.call(data);
  return tag.slice(8, -1).toLowerCase();
}

// 测试
console.log(getDataType(123));          // "number"
console.log(getDataType(null));         // "null"
console.log(getDataType([]));           // "array"
console.log(getDataType(new Date()));   // "date"
相关推荐
J***79391 小时前
前端在移动端中的React Native Windows
前端·react native·react.js
阿雄不会写代码1 小时前
PPTX报错AttributeError: module ‘collections‘ has no attribute ‘Container‘
前端
一点 内容1 小时前
AI搜索前端打字机效果实现方案演进:从基础到智能化的技术跃迁
前端·人工智能
GISer_Jing1 小时前
SEEConf大会分享——AI FOR FRONTEDN
前端·人工智能
我也爱吃馄饨1 小时前
前端视角下的浏览器LNA问题
前端·javascript·chrome
程序员爱钓鱼1 小时前
Node.js 的应用场景:为什么越来越多企业选择它?
前端·node.js·trae
程序员爱钓鱼1 小时前
为什么选择 Node.js?一文深入理解
前端·node.js·trae
二川bro1 小时前
内存泄漏检测:Python内存管理深度解析
java·开发语言·python
何以解忧,唯有..1 小时前
Vue 列表渲染
前端·javascript·vue.js