JavaScript instanceof 原理
instanceof 运算符用于检测对象的原型链是否包含某构造函数的 prototype,是判断继承关系的标准方式。
基本用法
JavaScript
// 检测对象是否为某类的实例
const arr = [1, 2, 3];
console.log(arr instanceof Array); // true
console.log(arr instanceof Object); // true(Array 继承 Object)
const obj = {};
console.log(obj instanceof Object); // true
console.log(obj instanceof Array); // false
function Foo() {}
const instance = new Foo();
console.log(instance instanceof Foo); // true
console.log(instance instanceof Object); // true
原理实现
JavaScript
// instanceof 检查左边对象的原型链是否包含右边的 prototype
// 实现原理:
function instanceofImpl(obj, constructor) {
// 右边必须是函数或有 prototype 的对象
if (typeof constructor !== 'function') {
throw new TypeError('Right-hand side must be a function');
}
// 获取对象原型
let proto = Object.getPrototypeOf(obj);
// 遍历原型链
while (proto !== null) {
if (proto === constructor.prototype) {
return true; // 找到匹配
}
proto = Object.getPrototypeOf(proto); // 继续向上查找
}
return false; // 原型链末端 null,未找到
}
// 测试
console.log(instanceofImpl([], Array)); // true
console.log(instanceofImpl([], Object)); // true
console.log(instanceofImpl({}, Array)); // false
原型链查找过程
JavaScript
function Animal() {}
function Dog() {}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
const dog = new Dog();
// instanceof 检查过程:
// dog instanceof Dog:
// dog.__proto__ === Dog.prototype ? → true
// dog instanceof Animal:
// dog.__proto__ === Animal.prototype ? → false
// dog.__proto__.__proto__ === Animal.prototype ? → true
// dog instanceof Object:
// dog.__proto__ === Object.prototype ? → false
// dog.__proto__.__proto__ === Object.prototype ? → false
// dog.__proto__.__proto__.__proto__ === Object.prototype ? → true
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true
console.log(dog instanceof Object); // true
与 typeof 对比
JavaScript
// typeof:返回数据类型(基本类型和 function)
console.log(typeof 'hello'); // 'string'
console.log(typeof 123); // 'number'
console.log(typeof true); // 'boolean'
console.log(typeof undefined); // 'undefined'
console.log(typeof null); // 'object'(历史 bug)
console.log(typeof []); // 'object'
console.log(typeof {}); // 'object'
console.log(typeof function(){}); // 'function'
// instanceof:检测对象的具体类
console.log([] instanceof Array); // true
console.log([] instanceof Object); // true
console.log({} instanceof Object); // true
// 组合使用:准确判断数组
const arr = [];
console.log(typeof arr); // 'object'
console.log(arr instanceof Array); // true
console.log(Array.isArray(arr)); // true(推荐)
边界情况
JavaScript
// null 和 undefined 不能用 instanceof
console.log(null instanceof Object); // false
console.log(undefined instanceof Object); // false
// 基本类型不是对象
console.log(123 instanceof Number); // false
console.log('hi' instanceof String); // false
console.log(true instanceof Boolean); // false
// 但包装对象是
console.log(new Number(123) instanceof Number); // true
console.log(new String('hi') instanceof String); // true
// Object.create(null) 无原型
const pureObj = Object.create(null);
console.log(pureObj instanceof Object); // false(原型链无 Object.prototype)
// 跨 iframe/窗口问题
// 不同环境的 Array.prototype 不同
const iframeArray = iframe.contentWindow.Array;
console.log([] instanceof iframeArray); // false(原型不匹配)
console.log(Array.isArray([])); // true(跨环境有效)
原型修改的影响
JavaScript
function Foo() {}
const instance = new Foo();
console.log(instance instanceof Foo); // true
// 修改原型后
Foo.prototype = {}; // 重写原型
console.log(instance instanceof Foo); // false(原型链断裂)
// 实例的原型指向旧原型
console.log(instance.__proto__ !== Foo.prototype); // true
// 新实例指向新原型
const newInstance = new Foo();
console.log(newInstance instanceof Foo); // true
isPrototypeOf 方法
JavaScript
// isPrototypeOf:检查对象是否在另一对象的原型链中
console.log(Array.prototype.isPrototypeOf([])); // true
console.log(Object.prototype.isPrototypeOf([])); // true
console.log(Foo.prototype.isPrototypeOf(instance)); // true
// 对比 instanceof
// obj instanceof Constructor 等价于
// Constructor.prototype.isPrototypeOf(obj)
function Foo() {}
const obj = new Foo();
console.log(obj instanceof Foo); // true
console.log(Foo.prototype.isPrototypeOf(obj)); // true
// isPrototypeOf 更灵活(不需要构造函数)
const proto = { x: 1 };
const obj = Object.create(proto);
console.log(proto.isPrototypeOf(obj)); // true
console.log(obj instanceof proto); // TypeError(右边必须是函数)
类型检测最佳实践
JavaScript
// 数组检测:优先使用 Array.isArray
console.log(Array.isArray([])); // true
console.log(Array.isArray(arguments)); // false
// 函数检测:typeof
console.log(typeof function(){}); // 'function'
// NaN 检测:Number.isNaN
console.log(Number.isNaN(NaN)); // true
// null 检测:严格相等
console.log(value === null);
// 自定义类检测:instanceof
class Dog extends Animal {}
const dog = new Dog();
console.log(dog instanceof Dog); // true
// 综合类型检测函数
function getType(value) {
if (value === null) return 'null';
if (value === undefined) return 'undefined';
if (Array.isArray(value)) return 'array';
if (typeof value === 'function') return 'function';
return typeof value;
}
注意事项
instanceof只适用于对象,基本类型返回 false- 右边必须是函数或有
prototype的对象- 原型被修改后可能导致检测结果变化
- 跨 iframe/窗口环境可能失效,用
Array.isArray替代
JavaScript
// instanceof 右边必须是函数
class Foo {}
console.log(new Foo() instanceof Foo); // true
// 错误示例
const proto = {};
console.log({} instanceof proto); // TypeError
// 正确使用 isPrototypeOf
console.log(proto.isPrototypeOf(Object.create(proto))); // true
要点总结
instanceof检查对象原型链是否包含构造函数的prototype- 从对象原型开始,沿
__proto__遍历直到null - 找到匹配返回 true,遍历结束返回 false
- 基本类型(非包装对象)instanceof 结果都是 false
Constructor.prototype.isPrototypeOf(obj)等价于obj instanceof Constructor- 数组检测优先使用
Array.isArray,跨环境有效
📝 发现内容有误?点击此处直接编辑