在面向对象语言里,我们经常需要回答一个问题: “这个对象到底是什么类型?”
在 JavaScript 中,除了 typeof、Object.prototype.toString,另一个非常重要的工具就是instanceof 运算符。
本文从几个实战示例出发,带你系统理解:
- instanceof 的真正含义
- 它与原型 / 原型链的关系
- 几种常见继承写法对 instanceof 的影响
- 如何手写一个简单版的 instanceof
我们天天写:
function Animal() {}
function Person() {}
Person.prototype = new Animal();
const p = new Person();
console.log(p instanceof Person); // true
console.log(p instanceof Animal); // true
但 instanceof 到底在判断什么?
1. 一句话原理
A instanceof B 干的事其实就一句话:
看
B.prototype在不在A的原型链上。
也就是从 A.__proto__ 一路往上找,
只要有一层等于 B.prototype,就算 true,
一直找到 null 还没找到,就是 false。
2. 用数组感受一下原型链
const arr = [];
console.log(arr.__proto__); // Array.prototype
console.log(arr.__proto__.__proto__); // Object.prototype
console.log(arr instanceof Array); // true
console.log(arr instanceof Object); // true
因为 arr 的原型链是:
arr → Array.prototype → Object.prototype → null
链上有谁,
instanceof 就会对谁返回 true。
3. 手写一个迷你版 instanceof
把刚才那句话翻译成代码,大概就是这个样子:
function myInstanceof(left, right) {
if (left == null || (typeof left !== 'object' && typeof left !== 'function')) {
return false;
}
let proto = Object.getPrototypeOf(left);
const target = right.prototype;
while (proto) {
if (proto === target) return true;
proto = Object.getPrototypeOf(proto);
}
return false;
}
你可以直接对比原生
instanceof 看结果是不是一样。
4. 继承写法对 instanceof 的影响(只记这三句)
- 只用
call/apply借构造函数:
只是拷贝属性,原型链没变,child instanceof Parent一般是false。 Child.prototype = new Parent():
原型链打通了,instanceof 能正确反映继承,但要记得改回constructor。Child.prototype = Object.create(Parent.prototype):
不共用同一个原型对象,更推荐,instanceof 结果也和预期一致。
5. 什么时候该用 instanceof?
- 判断“是不是我自定义的某个类型”:
value instanceof MyClass - 分辨一堆长得像的对象:猫狗猪都继承 Animal,但你只想特殊处理 Dog
- 排查继承/原型链写错了没:
console.log(obj.__proto__) + instanceof
判断内建类型(比如数组)时,Array.isArray 这类 API 通常更稳一点。
小结:
不需要把定义背得特别完整,记住一件事就够了:
instanceof 就是在原型链里查
prototype。
你会用这个思路画一条原型链,再手写一遍 myInstanceof,