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. 无法检测基本类型1 instanceof Number -> false (除非使用 new Number(1))。
  2. 原型链可伪造[].__proto__ = {}; [] instanceof Array -> false
  3. 多窗口环境 (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. 总结

  1. 基础类型 -> typeof (注意 null)。
  2. 引用类型 -> instanceof (注意 iframe)。
  3. 准确类型 -> Object.prototype.toString.call()