JavaScript数据类型分原始类型和对象类型,typeof对null错误返回"object",需结合Array.isArray()、Object.prototype.toString.call()和instanceof按场景选用;推荐用getType函数先判null再统一提取类型名。
JavaScript 数据类型就两类:原始类型(primitive)和对象类型(object),但判断方式不止一种,typeof、instanceof、Object.prototype.toString.call() 各有适用边界,用错就会翻车。
typeof null 返回 "object"
这是 JavaScript 诞生早期的底层实现 bug,一直保留至今以保证向后兼容。它本质是原始值,但 typeof 对其返回 "object" —— 所以不能单靠 typeof 判断是否为对象。
typeof null === "object" → true(错误归类)typeof [] === "object" → true(合理)typeof {} === "object" → true(合理)typeof new Date() === "object" → true(但其实是 Date 实例)这意味着:只要想准确区分 null、数组、正则、日期等,typeof 就不够用。
Array.isArray() 和 Object.prototype.toString.call() 怎么选判断是否为数组,优先用 Array.isArray() —— 它专为此设计,跨 iframe 也可靠;而 Object.prototype.toString.call() 是通用兜底方案,适合识别所有内置对象类型。
Array.isArray([]) → true
Array.isArray({}) → false
Object.prototype.toString.call([]) → "[object Array]"
Object.prototype.toString.call(/abc/) → "[object RegExp]"
Object.prototype.toString.call(new Map()) → "[object Map]"
注意:toString() 方法必须显式用 .call() 绑定目标值,否则直接调用会报错或返回字符串本身。
instanceof 的局限性:只适用于同一全局环境instanceof 检查原型链上是否存在某个构造函数的 prototype,但它在跨 iframe 或不同 JS 执行上下文时失效。
const iframe = document.createElement('iframe');
document.body.appendCh
ild(iframe);
const iframeArray = iframe.contentWindow.Array;
const arr = new iframeArray(1, 2, 3);
console.log(arr instanceof Array); // false(因为不是当前 window 的 Array)
obj instanceof MyClass),且确保类定义与实例在同一作用域
Date、RegExp),尤其涉及多上下文场景"str" instanceof String → false)别堆砌多种方法,按需组合。一个轻量、覆盖全的工具函数长这样:
function getType(value) {
if (value === null) return 'null';
if (typeof value === 'object') {
return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}
return typeof value;
}
// 使用示例:
getType(null); // "null"
getType([]); // "array"
getType(/a/); // "regexp"
getType(new Set()); // "set"
getType(42); // "number"
getType(BigInt(1)); // "bigint"
关键点:先单独处理 null,再用 toString.call() 统一提取类型名,避免 typeof 的歧义。别忘了 BigInt 和 Symbol 这类较新原始类型,typeof 能正确识别它们,所以不用额外 hack。