手写系列 | instanceof 原理及实现

102 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第12天,点击查看活动详情

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上

当看到 “判断一个值是什么类型有哪些方法?”、“说一说判断原型有哪些方法?” 这样的问题的时候,也许脑海里第一个想到的是 instanceof,除此之外还有其它的几种和类型相关的判断方案:

判断原型:

  • instanceof
  • in
    • 不管是不是在原型上,只要存在就是true
  • Object.hasOwnProperty
    • 判断某个属性是否在自己上面(不是原型上,如果属性在原型上会返回 false)

判断类型:

  • instanceof
  • typeof
    • 用于判断基本类型和引用类型
    • 局限性:判断null、array、object以及函数的实例(new Func())的时候,返回的都是 object
  • Object.prototype.toString.call()

使用 in 和 的结合,还可以判断属性是在对象本身还是来自原型链,true:来自原型链

function hasPrototypeProperty(obj, property) {
    return !obj.hasOwnProperty(property) && property in obj;
}

instanceof

instanceof可以对不同的实例对象进行判断,判断方法是根据对象的原型链依次向下查询

代码实现

思路:

  • 如果判断的数据是 基本数据类型 或者 null 直接返回 false
  • Object.getPrototypeOf() 获取参数的原型对象
  • 循环直到 原型对象为空(未找到)或 原型对象等于 target.prototype(已找到),否则再获取原型对象继续寻找
function myInstanceof (data, target) {
    if (!['function', 'object'].includes(typeof data) || data === null) return false
    // if(typeof data != 'object' && typeof data != 'function' || data == null){
    //     return false
    // }
    let proto = Object.getPrototypeOf(data)
    while (true) {
        if (proto == null) return false // proto == null 遍历完毕,还没找到
        if (proto == target.prototype) return true // 找到相同的原型对象
        proto = Object.getPrototypeOf(proto) // 继续找
    }
}
console.log(myInstanceof("hello", String)); // false
console.log(myInstanceof(new String("hello"), String)); // true
console.log(myInstanceof(Date, Function)); // true
console.log(myInstanceof(null, Object)); // false
console.log(myInstanceof({msg:111}, Object)); // true

运行结果:

image.png

注意

  1. instanceof 没法判断null
  2. 当判断不属于原型时,要注意 ! 的位置。正确写法:
if (!(orange instanceof Fruits)) {}

错误写法:当 orange 存在时,!orange 的取值会一直为 false,判断后的结果会一直为 false

if (!orange instanceof Fruits) {}

手写 instaceof

分为基本数据类型和引用数据类型判断