instanceof 操作符的原理及手写

intsanceof 是什么

instanceof 用于检测一个对象是不是另一个对象的实例。

用法

js 复制代码
obj instanceof Class
  • 如果 obj 隶属于 Class 类(或 Class 类的子类),则返回 true。例如:
js 复制代码
class Rabit {};
let rabit = new Rabit();

// rabit 是 Rabit 类的对象吗?
console.log(rabit instanceof Rabit); // true
  • instanceof 还适用于检测父类。
js 复制代码
class Animal { };
class Rabit extends Animal { };
let rabit = new Rabit();

// rabit 是 Animal 子类的对象吗?
console.log(rabit instanceof Animal); // true
// 判断对象实例的原型对象和类的原型对象是否一致可以确定obj是该类的实例还是父类的实例
console.log(Object.getPrototypeOf(rabit) === Animal.prototype); // false
  • 当然它也适用于构造函数的写法。
js 复制代码
function Animal() { };
function Rabit() { };

let ani = new Animal();
Rabit.prototype = ani; // 原型继承
let rabit = new Rabit();
let animal = new Animal();

console.log(rabit instanceof Rabit); // true
console.log(rabit instanceof Animal); // true
  • instanceof 只能正确判断引用数据类型 ,而不能正确判断基本数据类型。
js 复制代码
console.log(2 instanceof Number);                    // false
console.log(true instanceof Boolean);                // false 
console.log('str' instanceof String);                // false 

console.log([] instanceof Array);                    // true
console.log(function(){} instanceof Function);       // true
console.log({} instanceof Object);                   // true

基本数据类型不具备对象的特征,没有原型链可言,所以无法通过 instanceof 判断,应该使用 typeof。

实现原理

instanceof 的工作原理就是判断在一个对象原型链中能否找到该类型(构造函数)的原型。

它会顺着原型链依次去比较,直到obj.__prototype__ === Class.prototype为止。

ini 复制代码
obj.__proto__ === Class.prototype?
obj.__proto__.__proto__ === Class.prototype?
obj.__proto__.__proto__.__proto__ === Class.prototype?
...
// 如果任意一个的答案为 true,则返回 true
// 否则,如果我们已经检查到了原型链的尾端,则返回 false

像前面提到的 rabit instanceof Animal 这个例子,它会先和自身的原型对象匹配,再一直顺着原型链去和父类的原型对象匹配:

scala 复制代码
class Animal {}
class Rabbit extends Animal {}

let rabbit = new Rabbit();
alert(rabbit instanceof Animal); // true

// rabbit.__proto__ === Animal.prototype(无匹配)
// rabbit.__proto__.__proto__ === Animal.prototype(匹配!)

下图展示了 rabbit instanceof Animal 的执行过程中,Animal.prototype 是如何参与比较的:

手写instanceof

既然我们已经理解了原理,那么就来试试动手实现一个 Instanceof 吧。

js 复制代码
// left传入obj,right传入类
function myInstanceof(left, right) {
    // 遇到基本数据类型直接返回false,有些博客都漏了这一步
    if (typeof left !== 'object' || typeof left !== 'function' || left === null) {
        return false;
    };
    
    // 也可以通过Object.getPrototypeOf(left)拿到原型对象
    let proto = left.__proto__;
    let prototype = right.prototype;

    while (true) {
        // 已经到原型链尽头null
        if (!proto) return false;
        // 匹配,返回true
        if (proto === prototype) return true;
        // 顺着原型链更新指针
        proto = proto.__proto__;
    }
}

测试:

js 复制代码
function myInstanceof(left, right) {
    // 遇到基本数据类型直接返回false,有些博客都漏了这一步
    if (typeof left !== 'object' || typeof left !== 'function' || left === null) {
        return false;
    };
    
    // 也可以通过Object.getPrototypeOf(left)拿到原型对象
    let proto = left.__proto__;
    let prototype = right.prototype;

    while (true) {
        // 已经到原型链尽头null
        if (!proto) return false;
        // 匹配,返回true
        if (proto === prototype) return true;
        // 顺着原型链更新指针
        proto = proto.__proto__;
    }
}

console.log(myInstanceof(function () {}, Function)); // true
console.log(myInstanceof({}, Object)); // true
console.log(myInstanceof([], Function)); // false
console.log(myInstanceof(1, Number)); // false

如有问题欢迎在评论区讨论,一起进步!

相关推荐
Agent世界7 小时前
用 CDP 做发布自动化:四道机器闸门与产物验收
前端·javascript
FungLeo7 小时前
成为全栈·Vue 管理后台篇·编辑器图片上传:从文件选择到文章附件关联
前端·vue.js·编辑器·markdown·文件上传·formdata·附件管理
总要学点什么8 小时前
第104篇:三维特效-流动墙体效果——让贴图沿墙流动,它却只肯走一条对角线
开发语言·javascript·ecmascript·gis·webgl·材质·cesium
某哈压力大8 小时前
SSH 突然 Connection reset?不是密钥坏了,是 OpenSSL 把 sshd 干趴了
前端·node.js·命令行
程序员大阳8 小时前
副队长ES6+教程(3)--解构赋值
前端·javascript·es6·赋值·解构
神膘护体小月半8 小时前
css - 元素背景图由 hover 触发,初次加载时闪动的解决办法
前端·javascript·css
程序员大阳8 小时前
副队长ES6+教程(2)--let 与 const
前端·javascript·es6·const·let·var
deli0079 小时前
写满 200GB 后 SSD 为什么掉到 95MB/s?SLC 缓存模型实测
前端
nice_lcj5209 小时前
LRU 缓存入门:它是什么、怎么用、面试怎么手写
java·数据结构·缓存·面试·lru
曦樂~9 小时前
【Web Development】03JavaScript 基础和事件
开发语言·前端·javascript