标准答案
- instanceof 判断的是原型链关系:右侧构造函数的 prototype 是否出现在左侧对象的原型链上。
- 手写时先判断左侧是否为对象或函数,原始值直接返回 false;再取右侧构造函数的 prototype,沿着 Object.getPrototypeOf(left) 一层层向上查找。
- 如果某一层原型等于右侧 prototype,就返回 true;如果一直查到 null 还没找到,就返回 false。
- instanceof 不等于“这个对象一定由某构造函数创建”。Object.create 可以手动指定原型,Symbol.hasInstance 可以自定义判断行为,跨 iframe 或多 realm 场景也会影响内置类型判断。
题目解析
这里和原型链密切相关。手写时不能只看 constructor 属性,因为 constructor 可以被改写。
instanceof 的本质是沿原型链查找,不是检查构造函数调用记录。只要原型链能连上对应 prototype,就可能返回 true。
右侧必须是可调用且具有 prototype 语义的对象。箭头函数没有 prototype,某些自定义 Symbol.hasInstance 也会改变默认结果。
判断数组更推荐 Array.isArray,而不是 instanceof Array。Array.isArray 能更好处理跨 realm 的数组判断。
代码示例
下面是核心版 instanceof 实现,直接对应原型链查找过程。
JavaScript
function myInstanceof(value, Constructor) {
if (value === null || (typeof value !== 'object' && typeof value !== 'function')) {
return false
}
const targetPrototype = Constructor.prototype
let current = Object.getPrototypeOf(value)
while (current) {
if (current === targetPrototype) {
return true
}
current = Object.getPrototypeOf(current)
}
return false
}
function User() {}
const user = new User()
myInstanceof(user, User) // true
myInstanceof({}, User) // false常见误区
- 用 obj.constructor === Fn 实现 instanceof。
- 没有处理原始值左操作数。
- 忽略 Symbol.hasInstance 可以改变行为。