typeof
和 instanceof
都是 JavaScript 中用于类型检查的操作符,但它们的工作方式和应用场景有显著不同。
1. 基本区别对比
特性 | typeof |
instanceof |
---|---|---|
操作目标 | 适用于所有 JavaScript 值 | 只适用于对象 |
返回值 | 返回类型名称的字符串 | 返回布尔值 |
检查内容 | 检查值的类型 | 检查对象的原型链 |
对原始值的处理 | 有效 | 总是返回 false |
对数组的检查 | 返回 "object" | arr instanceof Array → true |
对 null 的检查 | 返回 "object"(历史遗留问题) | null instanceof Object → false |
跨窗口/框架问题 | 无影响 | 可能有影响 |
2. 详细区别解释
2.1 工作原理不同
typeof
:
- 返回一个表示操作数类型的字符串
- 对于原始值直接返回对应的类型名称
- 对于对象,通常返回 "object"(函数返回 "function")
javascript
typeof 42; // "number"
typeof "hello"; // "string"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof null; // "object" (历史遗留问题)
typeof {}; // "object"
typeof []; // "object"
typeof function(){}; // "function"
instanceof
:
- 检查构造函数的
prototype
属性是否出现在对象的原型链中 - 只对对象有效,原始值总是返回 false
javascript
[] instanceof Array; // true
[] instanceof Object; // true
new Date() instanceof Date; // true
42 instanceof Number; // false
"str" instanceof String; // false
2.2 对原始值的处理
typeof
可以正确处理原始值:
javascript
typeof 42; // "number"
typeof "hello"; // "string"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof null; // "object" (这是唯一例外)
instanceof
对原始值总是返回 false:
javascript
42 instanceof Number; // false
"hello" instanceof String; // false
true instanceof Boolean; // false
2.3 对数组的检查
typeof
无法区分数组和普通对象:
csharp
typeof []; // "object"
typeof {}; // "object"
instanceof
可以检测数组:
javascript
[] instanceof Array; // true
{} instanceof Array; // false
2.4 对 null 的检查
typeof
的著名陷阱:
csharp
typeof null; // "object" (这是历史遗留问题)
instanceof
正确处理 null:
javascript
null instanceof Object; // false
2.5 继承关系的检查
instanceof
可以检查继承关系:
scala
class Animal {}
class Dog extends Animal {}
let dog = new Dog();
dog instanceof Dog; // true
dog instanceof Animal; // true
typeof
无法检查继承关系:
csharp
typeof dog; // "object" (无法知道是Dog还是Animal)
3. 使用场景对比
适合使用 typeof
的情况
-
检查变量是否已定义:
csharpif (typeof variable === 'undefined') { // 变量未定义 }
-
检查基本类型:
javascriptfunction add(a, b) { if (typeof a !== 'number' || typeof b !== 'number') { throw new Error('参数必须是数字'); } return a + b; }
-
区分函数和其他对象:
iniif (typeof callback === 'function') { callback(); }
适合使用 instanceof
的情况
-
检查对象的具体类型:
javascriptif (value instanceof Date) { console.log(value.getFullYear()); }
-
检查自定义类的实例:
sqlclass User {} let user = new User(); if (user instanceof User) { // 处理用户对象 }
-
检查继承关系:
javaif (dog instanceof Animal) { // 处理动物对象 }
4. 特殊注意事项
4.1 跨窗口/框架问题
instanceof
在不同 iframe 或窗口之间可能不可靠:
javascript
// 假设array来自另一个iframe
let iframeArray = window.frames[0].Array;
let arr = new iframeArray(1, 2, 3);
console.log(arr instanceof Array); // false
解决方法:
javascript
console.log(Array.isArray(arr)); // true
4.2 构造函数原型被修改
修改构造函数的原型会影响 instanceof
的结果:
javascript
function Foo() {}
let foo = new Foo();
console.log(foo instanceof Foo); // true
// 修改原型
Foo.prototype = {};
console.log(foo instanceof Foo); // false
4.3 手动实现类型检查
对于更复杂的类型检查,可以结合使用:
javascript
function getType(obj) {
if (obj === null) return "null";
if (Array.isArray(obj)) return "array";
if (obj instanceof Date) return "date";
return typeof obj;
}
console.log(getType([])); // "array"
console.log(getType(null)); // "null"
console.log(getType(new Date())); // "date"
console.log(getType(42)); // "number"
5. 总结对比表
场景 | typeof |
instanceof |
推荐方案 |
---|---|---|---|
检查基本类型 | ✔️ 优秀 | ❌ 无效 | typeof |
检查数组 | ❌ 不足 | ✔️ 可用 | Array.isArray() |
检查 null | ❌ 陷阱 | ✔️ 正确 | obj === null |
检查函数 | ✔️ 优秀 | ❌ 无效 | typeof |
检查自定义类实例 | ❌ 不足 | ✔️ 优秀 | instanceof |
检查继承关系 | ❌ 无效 | ✔️ 优秀 | instanceof |
检查跨窗口对象 | ✔️ 可用 | ❌ 不可靠 | 特定API(如Array.isArray() ) |
6. 最佳实践建议
-
优先使用专用方法:
- 检查数组用
Array.isArray()
- 检查 null 用
obj === null
- 检查数组用
-
组合使用:
javascriptfunction isNumber(value) { return typeof value === 'number' || value instanceof Number; }
-
理解局限性:
typeof null
返回 "object"instanceof
对原始值无效- 跨窗口对象检查问题
-
考虑使用现代类型检查:
- TypeScript 提供编译时类型检查
- 使用
Object.prototype.toString.call()
更精确
通过理解 typeof
和 instanceof
的区别和适用场景,你可以更准确地编写类型检查逻辑,避免常见的 JavaScript 类型陷阱。