Javascript中的instanceof
一、语法
instanceof
是一个用于检测对象与构造函数之间关系的运算符,它会检查对象是否在构造函数的原型链上,返回一个布尔值(true
或 false
)。
对象 instanceof 构造函数
- 若
对象
的原型链中存在构造函数.prototype
,则返回true
;否则返回false
。
二、用法
1. 检测对象是否为某个构造函数的实例
// 构造函数
function Person() {}
// 创建实例
const p = new Person();// 检测 p 是否是 Person 的实例
console.log(p instanceof Person); // true(p 的原型链包含 Person.prototype)// 检测 p 是否是 Object 的实例(所有对象最终都继承自 Object)
console.log(p instanceof Object); // true(p 的原型链包含 Object.prototype)
2. 检测内置对象类型
const arr = [1, 2, 3];
const obj = { name: "张三" };
const str = new String("hello"); // 字符串对象(非基本类型)console.log(arr instanceof Array); // true(arr 是 Array 的实例)
console.log(obj instanceof Object); // true(obj 是 Object 的实例)
console.log(str instanceof String); // true(str 是 String 的实例)
注意:
instanceof
对基本数据类型(如'hello'
、123
)无效,因为它们不是对象:const str = "hello"; // 基本类型字符串 console.log(str instanceof String); // false
3. 在继承关系中检测
instanceof
会沿原型链向上查找,因此子类实例也会被检测为父类的实例:
// 父构造函数
function Animal() {}
// 子构造函数
function Dog() {}// 让 Dog 继承 Animal
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;// 创建子类实例
const dog = new Dog();console.log(dog instanceof Dog); // true(直接实例)
console.log(dog instanceof Animal); // true(父类,在原型链上)
console.log(dog instanceof Object); // true(顶级父类)
三、instanceof
的工作原理
instanceof
的检测逻辑可简单理解为以下步骤:
- 取构造函数的
prototype
(记为proto
)。 - 取对象的
__proto__
(记为objProto
)。 - 比较
objProto
是否等于proto
:- 若相等,返回
true
。 - 若不等,将
objProto
指向其原型(objProto = objProto.__proto__
),重复步骤 3。 - 直到
objProto
为null
(原型链终点),返回false
。
- 若相等,返回
模拟实现:
function myInstanceof(obj, Constructor) {// 基本类型直接返回 falseif (typeof obj !== "object" || obj === null) return false;let objProto = Object.getPrototypeOf(obj); // 获取 obj 的 __proto__const targetProto = Constructor.prototype; // 构造函数的 prototypewhile (true) {if (objProto === null) return false; // 到达原型链终点if (objProto === targetProto) return true; // 找到匹配的原型objProto = Object.getPrototypeOf(objProto); // 沿原型链向上查找}
}// 测试
console.log(myInstanceof(new Person(), Person)); // true
console.log(myInstanceof([], Array)); // true
四、与 constructor
的区别
特性 | instanceof | constructor |
---|---|---|
检测方式 | 沿原型链查找是否包含构造函数的 prototype | 直接指向创建对象的构造函数 |
继承场景 | 子类实例会被检测为父类的实例(true ) | 子类实例的 constructor 指向自身构造函数 |
可靠性 | 不受 constructor 被修改的影响 | 可被手动修改,可能导致判断错误 |
适用类型 | 仅适用于对象 | 可用于基本类型(通过包装对象) |
示例对比:
function Parent() {}
function Child() {}
Child.prototype = new Parent();
Child.prototype.constructor = Child; // 修复 constructorconst child = new Child();console.log(child instanceof Parent); // true(原型链包含 Parent.prototype)
console.log(child.constructor === Parent); // false(constructor 指向 Child)
五、注意事项
-
不能检测基本数据类型
如123 instanceof Number
、'abc' instanceof String
均返回false
(基本类型不是对象)。 -
原型被修改后可能失效
若构造函数的prototype
被重写,instanceof
检测结果可能不符合预期:function Person() {} const p = new Person(); Person.prototype = {}; // 重写原型console.log(p instanceof Person); // false(p 的原型链中已没有新的 Person.prototype)
-
跨窗口/iframe 问题
不同窗口的全局对象(如window
)不同,因此Array
、Object
等构造函数在不同窗口中是不同的引用,可能导致instanceof
检测错误:// 在 iframe 中创建的数组,在主窗口检测 const iframeArr = window.frames[0].Array; console.log(new iframeArr() instanceof Array); // false(不同窗口的 Array 原型不同)