JS - instanceOf 实现原理

139 阅读2分钟

前言

在实际的开发中,经常会遇到这种场景: 判断一个实例对对象是否为一个类的实例,这个时候我们有两种解决方法:即 instanceof 和constructor,前者指出对象是否为类/类的原型链上的一个实例,后者表示创建实例对象的构造函数。

instanceOf 实现

instanceOf 介绍

MDN中的定义介绍 image.png

通俗点理解就是: instanceOf用来判断一个实例是否在某个类的原型链上的任何位置,返回值是一个布尔值。

instanceOf 使用


function constructorFunB() {
    console.log('这是一个构造函数B');
}

function constructorFunC() {
    console.log('这是一个构造函数C');
}

const instanceObj = new constructorFunA();

constructorFunC.prototype = constructorFunA.prototype;

console.log(instanceObj instanceof constructorFunA); // true
console.log(instanceObj instanceof constructorFunB); // false
console.log(instanceObj instanceof constructorFunC); // true 
console.log(instanceObj instanceof Object); // true

上述代码中,为什么除constructorFunB,其余的打印都是true呢? 而constructorFunB又为什么打印为false呢?

  • constructorFunA

constructorFunA很好理解,通过new constructorFunA 得到的instanceObj, instanceObj是构造函数constructorFunA的实例对象,当然返回true

  • constructorFunB, 由于constructorFunB和constructorFunA没有任何的联系,也不在同一条原型链上,所以返回false

  • constructorFunC, 由于constructorFunC.prototype = constructorFunA.prototype,使得constructorFunC和constructorFunA的原型对象相同,所有返回true

  • Object, 由于原型链的顶端就是Object.prototype, 所以也会返回true

instanceOf 实现

根据上述的具体使用,可以得知,instanceOf的原理其实就是判断实例对象的__proto__ 是否等于构造函数的prototype,如果不等于,则会再它原型链上寻找,直到找到Object.prototype/null,根据找到的位置结果,返回最终的布尔值。

下面看具体的代码实现

function myInstanceOf(objInstance, constructorFun){
    const constructorFunPro = constructorFun.prototype;
    let objInstanceProto = objInstance.__proto__;
   
    while(true){
        // 原型链顶部还未找到,则返回false
        if(!objInstanceProto){
            return false;
        }
        if(objInstanceProto === constructorFunPro){
            return true;
        }
        // 当前原型对象不符合,则继续再原型对象的原型上继续查找
        constructorFunPro = constructorFunPro.__proto__
    }
}

总结

constructor 更加精确地指向对象所属的类,而对 instanceof 而言,即使是父类也会返回 true。 所以需要精确判断对象所属的累,建议使用constructor 。