instanceof 底层是原型链匹配,先判a是否为对象、b是否为函数,再用object.getprototypeof()沿[[prototype]]链查找b.prototype;__proto__已废弃,跨iframe因构造函数隔离而失效,symbol.hasinstance可自定义判断逻辑。

instanceof 的底层算法本质是原型链匹配,不是类型标签比对,也不是值的直接相等判断。它只关心“右边构造函数的 prototype 是否在左边对象的原型链上”——这个过程完全基于对象内部 [[Prototype]] 链的逐层向上查找。
核心步骤:三步定位法
JavaScript 引擎执行 a instanceof B 时,实际按以下逻辑运行:
- 先确认
a是对象或函数(原始值如"abc"、42、null、undefined直接返回false) - 再确认
B是函数(否则抛TypeError,因为只有函数才有prototype属性) - 取
B.prototype,然后从Object.getPrototypeOf(a)开始,反复调用Object.getPrototypeOf()向上遍历,直到找到匹配项或到达null
为什么不用 __proto__?
__proto__ 是历史遗留属性,非标准且已被标记为废弃。现代实现必须使用 Object.getPrototypeOf() —— 它是 ECMAScript 标准方法,能安全读取对象的内部 [[Prototype]],且兼容 Proxy、冻结对象等边界情况。手动实现若仍写 left.__proto__,在严格模式或某些环境(如 Deno、新版 Safari)中可能出错或返回 undefined。
跨 iframe 场景为何失效?
每个 iframe 拥有独立的全局执行环境,意味着各自的 Array、Date 等内置构造函数互不相等:iframe.contentWindow.Array !== Array。因此,即使一个数组来自 iframe,arr instanceof Array 会返回 false,因为它的原型链终点指向的是 iframe 内的 Array.prototype,而非当前上下文的 Array.prototype。这不是算法缺陷,而是原型链隔离的自然结果。
可被覆盖的行为:Symbol.hasInstance
构造函数可通过定义 [Symbol.hasInstance] 方法,完全接管 instanceof 的判断逻辑。例如:
class AlwaysTrue {
static [Symbol.hasInstance]() { return true; }
}
console.log({} instanceof AlwaysTrue); // true
此时引擎不再走原型链查找,而是直接调用该方法。这说明 instanceof 不是硬编码逻辑,而是可定制的协议——只要右侧值有该 symbol 方法,就优先执行它。











