typeof / instanceof / Object.prototype.toString.call
1. 核心对比
| 方法 | 适用场景 | 优势 | 劣势 |
|---|
| typeof | 基础类型检测 | 简单、快速 | 对引用类型只能返回 object (除了 function)。null 也会被误判为 object。 |
| instanceof | 引用类型 (对象) | 可以检测具体类型 (如 Array vs Object) | 基于原型链,可能失效 (iframe);无法检测基本类型。 |
| Object.prototype.toString | 全能王 | 最准确,可区分所有内置类型 | 代码略长,需 slice 截取。 |
2. 详细解析
(1) typeof
返回一个表示数据类型的字符串。
typeof undefined // "undefined"
typeof null // "object" (Bug)
typeof true // "boolean"
typeof 1 // "number"
typeof 10n // "bigint"
typeof "str" // "string"
typeof Symbol() // "symbol"
typeof function(){} // "function" (唯一可以区分的引用类型)
typeof {} // "object"
typeof [] // "object"
面试题:typeof 也有 TDZ 问题 (即使通常不报错)。
(2) instanceof
用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
[] instanceof Array // true
[] instanceof Object // true
function(){} instanceof Function // true
缺陷:
- 无法检测基本类型:
1 instanceof Number -> false (除非使用 new Number(1))。
- 原型链可伪造:
[].__proto__ = {}; [] instanceof Array -> false。
- 多窗口环境 (iframe):iframe 中的
Array 和父窗口的 Array 是两套构造函数,即使是真正的数组也会返回 false。
(3) Object.prototype.toString.call()
这是最完善的类型检测方案。它会返回 [object Type] 格式的字符串。
通用封装:
function getType(val) {
return Object.prototype.toString.call(val).slice(8, -1);
}
getType(null); // "Null"
getType(undefined); // "Undefined"
getType(1); // "Number"
getType(new Date()); // "Date"
getType(/test/); // "RegExp"
getType(Promise.resolve()); // "Promise"
3. 面试加分项
Q: 如何判断是否是数组?
- 优先推荐:
Array.isArray(arr) (ES5+)。
- 备选:
Object.prototype.toString.call(arr) === '[object Array]'。
- 不推荐:
instanceof (受环境影响)。
Q: constructor 属性靠谱吗?
非常不靠谱。因为 constructor 属性可以被任意修改,甚至被删除。它仅用于辅助查找构造函数,不能作为类型判断依据。
function A() {}
A.prototype.constructor = Array;
new A().constructor === Array; // true
4. 总结
- 基础类型 ->
typeof (注意 null)。
- 引用类型 ->
instanceof (注意 iframe)。
- 准确类型 ->
Object.prototype.toString.call()。