Object.prototype.toString.call()是最可靠的类型检测方式,它绕过原型链直接读取内部[[Class]]属性,返回如"[object Array]"的字符串,精准识别null、数组、正则、Symbol、BigInt等所有类型。

没错,Object.prototype.toString.call() 是 JavaScript 中最可靠、覆盖最全的类型检测方式。它不依赖构造函数、不被原型链污染、也不受 toString 方法重写影响,能精准返回每种值的内部标签。
为什么它比 typeof 更准
typeof 对基本类型还算友好,但一遇到 null、数组、正则、日期、Map、Set 等就全归为 "object";函数虽返回 "function",但这是特例,并非统一逻辑。而 Object.prototype.toString.call() 返回形如 "[object Array]"、"[object Date]"、"[object Null]" 的字符串,每个都明确对应内部类型标识([[Class]])。
-
typeof null→"object"(历史 bug) -
Object.prototype.toString.call(null)→"[object Null]" -
typeof []→"object" -
Object.prototype.toString.call([])→"[object Array]" -
typeof /abc/→"object" -
Object.prototype.toString.call(/abc/)→"[object RegExp]"
为什么它比 instanceof 更稳
instanceof 依赖原型链,一旦原型被修改(比如重赋值 Array.prototype 或使用跨 iframe 对象),结果就不可靠。而且它对原始值(如字符串字面量 "abc")无效,因为它们不是构造函数实例。
-
"hello" instanceof String→false(字面量不是new String()) -
Object.prototype.toString.call("hello")→"[object String]" - iframe 中创建的数组,
arr instanceof Array→false(不同全局环境) -
Object.prototype.toString.call(arr)→ 仍是"[object Array]"
它怎么工作的:核心原理
每个内置对象(Array、Date、RegExp 等)都重写了自己原型上的 toString 方法,用于格式化输出(如 [1,2].toString() === "1,2")。而 Object.prototype.toString 是“未被覆盖”的原始版本,它不关心具体值,只读取对象内部的 [[Class]] 内部属性并格式化为固定字符串。
- 调用
call(obj)是为了把this强制绑定到传入的对象上 - 即使
obj是null或undefined,该方法也能安全返回"[object Null]"或"[object Undefined]" - 它不调用对象自身的
toString,而是绕过原型链,直接使用 Object 原型上的原始实现
实用封装建议
日常开发中可封装成简洁工具函数,提取类型名:
function getType(value) {
return Object.prototype.toString.call(value).slice(8, -1);
}
// 使用示例:
getType(123); // "Number"
getType([]); // "Array"
getType(new Date()); // "Date"
getType(null); // "Null"
getType(undefined); // "Undefined"
getType(Symbol()); // "Symbol"
getType(42n); // "BigInt"
注意:ES6+ 新增类型(Symbol、BigInt、Promise、Map、Set 等)也都被该方法正确识别,无需额外 polyfill。


















