typeof对基本类型和函数可靠但无法区分null及引用类型;instanceof依赖构造器引用且跨环境失效;Object.prototype.toString.call()最稳妥,可精准识别所有内置类型。
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 检查的是对象原型链上是否存在指定构造函数的 prototype,所以它依赖运行时的构造器引用,且只对“由该构造器创建”的实例有效。
[] instanceof Array // true
new Date() instanceof Date // true
{a:1} instanceof Object // true
但它在跨 iframe 或不同 JS 执行上下文(如微前端、Web Worker)中会失效,因为不同环境下的 Array 构造器不是同一个引用:
iframe.contentWindow.Array !== Array,导致 iframeArr instanceof Array 为 false
instanceof 判断可能意外失败123、"str")直接使用会报错:123 instanceof Number 是 false,且不推荐包装成对象再判断几乎所有内置类型在调用 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,但别用于跨模块边界getType() 封装,避免漏判 null 或误判数组最容易被忽略的是 null 和 undefined 的区分,以及跨环境对象检测——这两个点一旦出错,往往表现为“明明是数组却进不了 if 分支”,调试起来反而比写错逻辑更耗时。