instanceof 和 typeof 的区别与正确用法
很多前端开发者经常困惑:什么时候该用 instanceof,什么时候该用 typeof?这两个操作符看起来都用于类型检查,但它们的用途和原理完全不同。
快速了解基本语法
instanceof 的语法很简单:
object instanceof Constructor // 返回 true 或 false左边是要检查的对象,右边是构造函数。简单说,就是检查对象是否属于某个构造函数的实例。
typeof 的用法更直接:
typeof value // 返回类型字符串instanceof 的工作原理:查找原型链
instanceof 的核心是检查对象的原型链。它的工作流程是这样的:
获取对象的原型:Object.getPrototypeOf(obj)
获取构造函数的原型属性:Constructor.prototype
沿着原型链向上查找,直到:
找到匹配的原型 → 返回 true
找到 null 还没有匹配 → 返回 false
用代码来模拟这个过程:
function instanceOf(obj, Ctor) {
if (typeof obj !== 'object' || obj === null) return false;
let proto = Object.getPrototypeOf(obj);
while (proto) {
if (proto === Ctor.prototype) return true;
proto = Object.getPrototypeOf(proto);
}
return false;
}实际例子理解原型链
假设我们有这样的继承关系:
function Animal() {}
function Dog() {}
Dog.prototype = Object.create(Animal.prototype);
const d = new Dog();原型链是这样的:
d → Dog.prototype → Animal.prototype → Object.prototype → null检查结果:
d instanceof Dog // true,第一层匹配
d instanceof Animal // true,第二层匹配
d instanceof Object // true,第三层匹配
d instanceof Cat // false,整个链都没有 Cat.prototypeinstanceof 的常见问题
1. 原始类型返回 false
"abc" instanceof String // false
123 instanceof Number // false
true instanceof Boolean // false只有使用 new 创建的包装对象才会返回 true:
new String('abc') instanceof String // true2. 跨框架问题
在不同 iframe 或窗口中,相同的构造函数会有不同的原型:
// 在 iframe A 中
const iframeArray = window.frames[0].Array;
const arr = [];
arr instanceof Array // true
arr instanceof iframeArray // false3. 修改 prototype 的影响
function F() {}
const o = new F();
F.prototype = {}; // 修改了原型
console.log(o instanceof F); // false4. 自定义 instanceof 行为
ES6 引入了 Symbol.hasInstance,可以自定义 instanceof 的行为:
class MyArray {
static [Symbol.hasInstance](obj) {
return Array.isArray(obj) && obj.length > 3;
}
}
[1,2,3,4] instanceof MyArray; // true
[1,2] instanceof MyArray; // falseinstanceof 与 typeof 对比
| 值 | typeof 结果 | instanceof 检查 | 说明 |
|---|---|---|---|
| [] | 'object' | Array | typeof 无法区分数组和对象 |
| {} | 'object' | Object | 同上 |
| new String('') | 'object' | String | 包装对象 |
| function fn(){} | 'function' | Function | typeof 能识别函数 |
| null | 'object' | 任何都是 false | JavaScript 的历史问题 |
| "hello" | 'string' | String → false | 原始类型 |
实际应用:安全的类型检查
检查数组的推荐方法
// 不推荐的方法
const isArray = value => value instanceof Array;
// 推荐的方法
const isArray = value => Array.isArray(value);Array.isArray() 比 instanceof 更好,因为它:
性能更好
解决跨框架问题
代码意图更清晰
实用的类型检查函数
function getType(value) {
// 先处理 null
if (value === null) return 'null';
// 处理其他类型
const type = typeof value;
if (type !== 'object') return type;
// 详细的对象类型检查
if (Array.isArray(value)) return 'array';
if (value instanceof Date) return 'date';
if (value instanceof RegExp) return 'regexp';
return 'object';
}使用建议和最佳实践
1. 基础类型检查用 typeof
// 检查是否是字符串
if (typeof value === 'string') {
// 处理字符串
}
// 检查是否是函数
if (typeof callback === 'function') {
callback();
}2. 对象类型检查用 instanceof
// 检查是否是日期对象
if (value instanceof Date) {
console.log(value.getFullYear());
}
// 检查是否是自定义类的实例
if (employee instanceof Manager) {
employee.approveRequest();
}3. 特殊情况的处理
// 处理 null 和 undefined
if (value == null) {
// 同时处理 null 和 undefined
}
// 安全的属性访问
if (typeof obj?.property === 'string') {
// 使用可选链避免错误
}常见误区避免
不要用 instanceof 检查原始类型
// 错误
if (value instanceof String) {
// 这只会对 new String('') 返回 true
}
// 正确
if (typeof value === 'string') {
// 对字符串字面量和 String 对象都有效
}注意构造函数的变化
function User(name) {
this.name = name;
}
const user1 = new User('张三');
User.prototype = {}; // 修改原型
const user2 = new User('李四');
console.log(user1 instanceof User); // false
console.log(user2 instanceof User); // true进阶技巧
实现多重继承检查
class Animal {}
class Flyable {
static [Symbol.hasInstance](obj) {
return typeof obj.fly === 'function';
}
}
class Bird extends Animal {
fly() {}
}
const bird = new Bird();
console.log(bird instanceof Animal); // true
console.log(bird instanceof Flyable); // true安全的类型判断函数
function safeTypeCheck(value, type) {
if (typeof type === 'function') {
return value instanceof type;
}
switch (type) {
case 'array': return Array.isArray(value);
case 'null': return value === null;
case 'undefined': return value === undefined;
default: return typeof value === type;
}
}总结
记住这几个要点:
typeof 用于检查原始类型和函数,返回类型字符串
instanceof 用于检查对象是否是某个构造函数的实例,检查原型链
原始类型 用 typeof 检查,对象类型用 instanceof 检查
跨框架 时使用 Array.isArray() 等内置方法
注意原型修改 对 instanceof 结果的影响
在实际开发中,根据具体需求选择合适的类型检查方法。对于基础类型,typeof 更合适;对于复杂的对象类型,instanceof 更准确。理解它们的原理和差异,能帮助你写出更健壮的代码。
本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!