JS中instanceof运算符实际工作原理及检测差异解析
现象原因解释
你找到的手写instanceof实现和原生运算符行为不一致,核心差异是原生instanceof会先对左侧操作数做类型校验,而手写实现直接访问__proto__触发了JavaScript的隐式装箱行为:
- 当你在原始值(比如数字字面量
10)上访问__proto__属性时,JS引擎会临时将原始值转换为对应的包装对象(等价于临时生成new Number(10))再访问属性,因此(10).__proto__ === Number.prototype会返回true,手写函数顺着原型链能匹配到Number.prototype,自然返回true。 - 原生
instanceof运算符不会触发这个装箱操作,只要左侧操作数是原始类型,直接返回false,这就是10 instanceof Number返回false的根本原因。
原生instanceof运算符的执行逻辑
遵循ECMAScript规范,a instanceof b的执行步骤为:
- 校验右侧操作数
b是否为可调用对象(即函数/类),如果不满足直接抛出类型错误。 - 读取右侧操作数的
prototype属性,记为targetPrototype。 - 校验左侧操作数
a的类型:如果a不是对象类型(即属于原始值范畴:number、string、boolean、null、undefined、symbol、bigint),直接返回false。 - 读取
a的隐式原型a.__proto__记为currentProto,开始循环遍历原型链:- 若
currentProto为null,说明已经遍历到原型链顶端,返回false - 若
currentProto === targetPrototype,说明匹配成功,返回true - 否则将
currentProto更新为currentProto.__proto__,回到上一步继续判断
- 若
对齐原生行为的手写实现
按照上述逻辑修正后的手写代码如下:
function instance_of(V, F) { // 校验右侧参数是否为合法构造函数 if (typeof F !== 'function') { throw new TypeError('Right-hand side of instanceof is not callable') } const targetPrototype = F.prototype // 左侧为原始值直接返回false if (V === null || (typeof V !== 'object' && typeof V !== 'function')) { return false } let currentProto = V.__proto__ while (true) { if (currentProto === null) return false if (currentProto === targetPrototype) return true currentProto = currentProto.__proto__ } }
测试结果和原生行为完全一致:
console.log( (10).__proto__ === Number.prototype ) // true console.log( instance_of(10, Number ) ) // false console.log( 10 instanceof Number ) // false console.log( instance_of(new Number(10), Number) ) // true console.log( new Number(10) instanceof Number ) // true
补充:所有原始值直接通过
instanceof判断对应包装类都会返回false,包括'' instanceof String、true instanceof Boolean、1n instanceof BigInt,只有显式通过new创建的包装对象实例,才会返回true。
内容的提问来源于stack exchange,提问作者MurphyChen
相关产品推荐
相关产品推荐

