最可靠的数据类型检测方案是object.prototype.tostring.call(),它能准确区分null、array、date等类型,且跨iframe兼容,返回如"[object array]"格式的字符串。

<p>JavaScript 原生的 <code>typeof</code> 和 <code>instanceof</code> 都有明显缺陷:比如 <code>typeof null === 'object'</code>、<code>Array</code> 和 <code>Date</code> 都被 <code>typeof</code> 判为 <code>'object'</code>,而 <code>instanceof</code> 在跨 iframe 场景下会失效。要真正精确检测数据类型,必须结合 <code>Object.prototype.toString.call()</code> —— 它是 JS 中最可靠、可跨环境、且能区分内置构造器的方案。</p> <h3>核心原理:用 <code>toString</code> 获取内部标签</h3> <p><code>Object.prototype.toString</code> 在规范中定义为返回对象的 [[Class]] 内部属性,格式为 <code>[object Xxx]</code>。对任意值调用 <code>Object.prototype.toString.call(x)</code>,都能得到标准化的类型标识:</p>
-
Object.prototype.toString.call([])→"[object Array]" -
Object.prototype.toString.call(new Date())→"[object Date]" -
Object.prototype.toString.call(null)→"[object Null]" -
Object.prototype.toString.call(undefined)→"[object Undefined]" -
Object.prototype.toString.call(123)→"[object Number]"
基础版:返回标准类型字符串
封装一层,提取括号内首字母大写的类型名:
<code>function typeOf(value) {
const str = Object.prototype.toString.call(value);
return str.slice(8, -1); // 去掉 "[object " 和 "]"
}</code>
这样 typeOf([1,2]) 返回 "Array",typeOf(null) 返回 "Null",typeOf(/abc/) 返回 "RegExp" —— 全部准确、无歧义、兼容所有环境。
增强版:支持布尔判断与类型断言
实际开发中常需判断是否为某类型,可扩展为链式工具函数:
<code>function typeOf(value) {
const raw = Object.prototype.toString.call(value);
const typeName = raw.slice(8, -1);
return {
is: (t) => typeName === t,
isString: () => typeName === 'String',
isNumber: () => typeName === 'Number',
isBoolean: () => typeName === 'Boolean',
isNull: () => typeName === 'Null',
isUndefined: () => typeName === 'Undefined',
isArray: () => typeName === 'Array',
isObject: () => typeName === 'Object',
isFunction: () => typeName === 'Function',
isDate: () => typeName === 'Date',
isRegExp: () => typeName === 'RegExp',
isPromise: () => typeName === 'Promise',
isMap: () => typeName === 'Map',
isSet: () => typeName === 'Set',
isWeakMap: () => typeName === 'WeakMap',
isWeakSet: () => typeName === 'WeakSet',
isSymbol: () => typeName === 'Symbol',
isBigInt: () => typeName === 'BigInt',
isTypedArray: () => /Array$/.test(typeName) && typeName !== 'Array',
toString: () => typeName
};
}</code>
用法示例:typeOf([1,2]).isArray() → true;typeOf(new Promise(() => {})).isPromise() → true;typeOf(new Uint8Array()).isTypedArray() → true。
注意事项与边界处理
这个方案几乎覆盖全部场景,但仍需注意几点:
- 自定义类实例(如
class A {})仍返回"Object",因未重写Symbol.toStringTag—— 若需识别,应主动设置:A.prototype[Symbol.toStringTag] = 'A' - ES6+ 新增类型(如
Promise、Map)在旧引擎(如 IE)中可能不支持,使用前建议按需 polyfill 或降级处理 - 对于原始值包装对象(如
new String('a')),返回"String"而非"Object",符合语义预期 - 不要用
value.constructor.name替代 —— 构造器可被篡改,且跨 iframe 失效











