object.prototype.tostring.call 是最可靠跨环境的类型识别方式,能精准区分内置对象和自定义实例;typeof 无法区分引用类型,instanceof 在多全局环境失效且不支持新原始类型。

用 Object.prototype.toString.call 是目前最可靠、跨环境兼容的类型识别方式,尤其适合区分内置对象(如 Date、RegExp、Map)和自定义构造函数实例。
为什么 typeof 和 instanceof 不够用
typeof 对多数引用类型都返回 "object",无法区分 Array、Date、null;instanceof 在多全局环境(如 iframe、微前端)下会失效,且对原始值(new String('a') 以外的字符串)或 Symbol、BigInt 等新类型支持弱。
-
typeof [] === "object"—— 和普通对象一样 -
{} instanceof Object为true,但new Date() instanceof Object也是true,无法进一步区分 -
iframe.contentWindow.Array !== Array,导致[].constructor === iframe.contentWindow.Array时instanceof Array返回false
toString.call 的原理与标准格式
每个对象内部都有一个 [[Class]] 内部属性(ES5 规范),Object.prototype.toString 方法会读取它并返回形如 "[object Type]" 的字符串。虽然 ES6 后该属性被 [[NativeBrand]] 和 Symbol.toStringTag 替代,但 toString.call 仍按约定行为工作。
-
Object.prototype.toString.call([])→"[object Array]" -
Object.prototype.toString.call(new Date())→"[object Date]" -
Object.prototype.toString.call(/abc/)→"[object RegExp]" -
Object.prototype.toString.call(null)→"[object Null]" -
Object.prototype.toString.call(undefined)→"[object Undefined]"
识别自定义构造函数实例
默认情况下,自定义构造函数生成的实例会被识别为 "[object Object]"。要精准识别,需在实例上设置 Symbol.toStringTag 属性(推荐)或改写 toString 方法(不推荐)。
- ✅ 推荐:在构造函数原型上定义
Symbol.toStringTag
function MyClass() {}
MyClass.prototype[Symbol.toStringTag] = 'MyClass';
const inst = new MyClass();
Object.prototype.toString.call(inst); // "[object MyClass]"
- ⚠️ 注意:
Symbol.toStringTag必须是字符串字面量,不能是表达式或变量 - ❌ 避免重写
toString,否则可能破坏 JSON 序列化或调试工具识别
封装一个安全的类型判断工具
可提取标签名,统一处理大小写和空格,适配常见类型判断场景:
function getType(obj) {
const str = Object.prototype.toString.call(obj);
return str.slice(8, -1); // 去掉 "[object " 和 "]"
}
// 使用示例
getType([]); // "Array"
getType(new Set()); // "Set"
getType(new URL('https://a.com')); // "URL"
getType(class {}); // "Function"
- 返回值全大写首字母(如
"Date"、"Promise"),便于 switch 或 map 匹配 - 对原始值也有效:
getType(42)→"Number",getType(BigInt(1))→"BigInt" - 注意:
getType(arguments)返回"Arguments",不是"Array"










