⭐ 推荐:社区规则条款 V1.0

js 判断数据类型有哪些方法

GJ论坛站长
GJ论坛站长 管理员资深会员 👑黑卡会员
发布于 2026-10-22 02:30 ·4 浏览 ·0 回复
内容摘要

判断 JavaScript 数据类型应组合使用 typeof 判断基本类型与函数、Array.isArray 跨 realm 判断数组、Object.prototype.toString.call 兜底判断内置对象、instanceof 判

JavaScript 判断数据类型没有单一万能方法,工程上的标准组合是:typeof 打底判断基本类型、Array.isArray() 单独判数组、Object.prototype.toString.call() 兜底判断内置对象、instanceof 用于自定义类,四者按场景分工使用,任何单一方法都会漏判。

typeof 能判断哪些类型,哪些判断不了?

typeof 的结论是:它能准确返回 8 种字符串结果,但对 null 和所有内置引用类型全部失效。

typeof 返回值为 "undefined"、"boolean"、"number"、"string"、"symbol"、"bigint"、"function"、"object" 之一。也就是说,基本类型(除 null 外)它都能区分,函数也能单独识别出来,但数组、日期、正则、Map、Set、普通对象统统返回 "object",无法再细分。

两个必须记住的历史坑:

typeof null        // "object"  ← 1995 年 JS 引擎用低位标签存类型,null 的标签全 0 被误判为对象,至今未修
typeof []          // "object"
typeof new Date()  // "object"
typeof NaN         // "number"  ← NaN 也是 number,要判它必须用 Number.isNaN()

结论:typeof 只能用来排除「是不是基本类型 / 是不是函数」,不能用来判断「是不是数组 / 是不是日期」。

instanceof 和 constructor 有什么坑?

instanceof 的结论是:它沿着原型链判断构造器,只对对象有效,且跨 iframe(跨 realm)必然失效。

[] instanceof Array        // true
[] instanceof Object       // true,因为 Array.prototype 原型链上有 Object.prototype
'abc' instanceof String    // false,基本类型没有原型链

跨 realm 失效的例子:在 iframe 里 new Array(),父页面用 instanceof Array 判断会返回 false,因为两边是不同的 Array 构造器。这是 Array.isArray() 存在的根本原因——它在 ES5 中被规定为跨 realm 可靠。

constructor 的坑更明显:obj.constructor 可以被改写,也可以被 Object.create(null) 抹掉,且遇到 null / undefined 直接抛 TypeError。所以 obj.constructor === Array 这种写法只适合内部可控对象,不适合判断外部传入的数据。

Object.prototype.toString.call 为什么最通用?

Object.prototype.toString.call(x) 的结论是:它是判断内置对象类型最通用的方法,返回 [object Type] 格式字符串,能区分 10 种以上内置类型。

const type = x => Object.prototype.toString.call(x).slice(8, -1);

type([])            // "Array"
type(null)          // "Null"
type(new Date())    // "Date"
type(/abc/)         // "RegExp"
type(new Map())     // "Map"
type(function(){})  // "Function"
type(123)           // "Number"

它之所以可靠,是因为它读取的是对象内部的 [[Class]] 内部槽(ES6 后改为读 Symbol.toStringTag),不依赖原型链,跨 realm 也稳定。

一个边界情况必须注意:如果对象自定义了 Symbol.toStringTag,结果会被改写。

const o = { [Symbol.toStringTag]: 'MyType' };
type(o)  // "MyType"

所以这个方法对自定义类也不完全可信,用它判断内置类型没问题,判断业务对象仍要配合 instanceof。

实际项目里应该怎么组合判断?

结论:写一个分层判断的 getType 函数,基本类型走 typeof,null 单独拦截,数组走 Array.isArray,其余内置对象走 toString,自定义类走 instanceof,是当前最稳的写法。

function getType(x) {
  if (x === null) return 'null';
  const t = typeof x;
  if (t !== 'object') return t;          // undefined/boolean/number/string/symbol/bigint/function
  if (Array.isArray(x)) return 'array';  // 跨 realm 可靠
  return Object.prototype.toString.call(x).slice(8, -1).toLowerCase();
}

几个高频场景的固定结论:

  • 判断数组:只用 Array.isArray(),不要用 typeof、instanceof、constructor。
  • 判断 NaN:只用 Number.isNaN(),x !== x 虽等价但可读性差,isNaN() 会先做类型转换把 "abc" 也判成 true。
  • 判断普通对象:type(x) === 'Object',要排除数组和 null。
  • 判断是否 Promise:x instanceof Promise 在跨库场景不可靠(不同 Promise 实现),改用 typeof x?.then === 'function' 的鸭子类型判断。
  • 判断空对象:Object.keys(x).length === 0,不要用 JSON.stringify(x) === '{}',后者受属性顺序和 undefined 影响。

总结一下:typeof 负责基本类型和函数,Array.isArray 负责数组,Object.prototype.toString.call 负责其余内置对象,instanceof 只留给自定义类。四者组合而不是互相替代,才是 JS 类型判断的稳定方案;constructor 和裸 instanceof 判断内置类型都应尽量避免。

本文转载自 GJ站长论坛,原文地址:https://www.gj0.com/thread-2366.html
转载请注明出处,版权归原作者所有。
—/ 5暂无评分
还没有评分,来打第一分吧

全部回复 0

还没有回复,来抢沙发~