typeof对基本类型和函数可靠但无法区分null及引用类型;instanceof依赖构造器引用且跨环境失效;Object.prototype.toString.call()最稳妥,可精准识别所有内置类型。

typeof 对基本类型和函数的判断是可靠的
typeof 在区分 string、number、boolean、undefined、function 时表现稳定,比如:
typeof "hello" // "string"
typeof 42 // "number"
typeof true // "boolean"
typeof undefined // "undefined"
typeof function(){} // "function"
但它的短板非常明显:typeof null 返回 "object",这是历史遗留 bug;对所有引用类型(Array、Date、RegExp、普通对象等)一律返回 "object",完全无法区分。
- 遇到
null时必须额外用value === null单独判断 -
typeof []和typeof {}都是"object",没法知道是不是数组 -
typeof new Date()也是"object",看不出是日期实例
instanceof 适合检测自定义类或明确构造器来源的对象
instanceof 检查的是对象原型链上是否存在指定构造函数的 prototype,所以它依赖运行时的构造器引用,且只对“由该构造器创建”的实例有效。
[] instanceof Array // true
new Date() instanceof Date // true
{a:1} instanceof Object // true
但它在跨 iframe 或不同 JS 执行上下文(如微前端、Web Worker)中会失效,因为不同环境下的 Array 构造器不是同一个引用:
立即学习“Java免费学习笔记(深入)”;
-
iframe.contentWindow.Array !== Array,导致iframeArr instanceof Array为false - ES6 模块中如果导出/导入了类,需确保构造器引用一致,否则
instanceof判断可能意外失败 - 对原始值(
123、"str")直接使用会报错:123 instanceof Number是false,且不推荐包装成对象再判断
Object.prototype.toString.call() 是最稳妥的通用方案
几乎所有内置类型在调用 Object.prototype.toString.call(value) 时都会返回形如 "[object Xxx]" 的字符串,包括 null 和 undefined:
Object.prototype.toString.call(null) // "[object Null]" Object.prototype.toString.call(undefined) // "[object Undefined]" Object.prototype.toString.call([]) // "[object Array]" Object.prototype.toString.call(new Date()) // "[object Date]" Object.prototype.toString.call(/abc/) // "[object RegExp]"
这个方法不依赖构造器引用,也不受执行上下文影响,是目前最可靠的类型探测方式。可封装成工具函数:
function getType(value) {
return Object.prototype.toString.call(value).slice(8, -1);
}
getType([1,2]) // "Array"
getType(new Set()) // "Set"
- 注意:不能省略
.call(),直接{}.toString()会走对象自己的toString方法,返回"[object Object]" - 对自定义类,需在类上显式定义
Symbol.toStringTag才能被识别为对应标签,否则仍是"Object" - 性能上比
typeof稍慢,但日常类型判断几乎无感知,不必过早优化
实际项目中怎么选:按场景分层处理
没必要死守某一种方法。多数真实代码里,组合使用更高效也更安全:
- 快速判断是否为原始类型或函数 → 用
typeof - 确认某个值是否为数组 → 优先用
Array.isArray()(标准、快、兼容好) - 需要精确识别
Date、RegExp、Map等 → 用Object.prototype.toString.call() - 判断是否为某自定义类实例且确定同上下文 → 可用
instanceof,但别用于跨模块边界 - 涉及序列化、表单校验、API 响应解析等场景 → 建议统一用
getType()封装,避免漏判null或误判数组
最容易被忽略的是 null 和 undefined 的区分,以及跨环境对象检测——这两个点一旦出错,往往表现为“明明是数组却进不了 if 分支”,调试起来反而比写错逻辑更耗时。










