持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第15天,点击查看活动详情
前言
JS 中自带的 instanceof 方法,可以判断出右侧构造函数的prototype,是否位于左侧对象的原型链上。
本文通过手写实现 instanceof,了解其使用和原理。
代码
首先,还是先定义对应函数,确定参数和返回值。
参数可以确定至少有两个,一个是被查询的对象,一个是对应的构造函数;返回值应该是 boolean 类型,默认返回 false,所以代码如下:
/**
* 实现 instanceof
* @param { any } instance 构造实例
* @param { Object } builder 目标构造函数
* @returns { boolean }
*/
function myInstanceof (instance, builder) {
return false
}
需要注意的是,JS 中 instanceof 左侧可以是任何类型的值,但如果不是 Object 对象,就直接返回 fasle,如下:
但是,如果这个基本类型的变量是通过 new 生成的,却可以使用 instanceof 进行判断:
因为通过 new 创建的,都是一个对象,符合 instanceof 的规则:
所以,手写的 myInstanceof 的第一步就是对参数进行检测,如果不符合要求,返回 false,代码如下:
function myInstanceof (instance, builder) {
// 这种写法,排除 instance 是 null 和 undefined
let __proto__ = instance && instance.__proto__
const builderPrototype = builder && builder.prototype
// 类型检测
// 如果 `instance` 不是 `Object` 类型,返回 false
// 判断 `instance` 上不存在原型链,或者 `builder` 上不存在 `prototype`,返回 false
if (typeof instance !== 'object' || !builderPrototype || !__proto__) {
return false
}
return false
}
然后就是判断 builderPrototype 是否存在于 instance 的原型链上,因为不知道原型链上共有多少层,所以,基本需要递归或者循环来进行逐层判断,直到原型链到尽头或者原型链上的某一层就是 builderPrototype,代码如下;
function myInstanceof (instance, builder) {
// 类型检测
let __proto__ = instance && instance.__proto__
const builderPrototype = builder && builder.prototype
if (typeof instance !== 'object' || !builderPrototype || !__proto__) {
return false
}
// 循环检测,直到原型链为 null
while (__proto__) {
// 如果找到,返回 true,结束循环
if (__proto__ === builderPrototype) {
return true
}
// 逐层读取原型链
__proto__ = __proto__.__proto__
}
// 循环结束,表明没有找到,返回 false
return false
}
至此,一个基本的 myInstanceof 就实现了,测试一把:
console.log('my instanceof 1:', myInstanceof(1, Number))
console.log('my instanceof 2:', myInstanceof(new String('abc'), String))
console.log('my instanceof 3:', myInstanceof(person, Person))