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

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

相关推荐
满怀10153 分钟前
【Flask全栈开发指南】从零构建企业级Web应用
前端·python·flask·后端开发·全栈开发
小杨升级打怪中30 分钟前
前端面经-webpack篇--定义、配置、构建流程、 Loader、Tree Shaking、懒加载与预加载、代码分割、 Plugin 机制
前端·webpack·node.js
每次的天空35 分钟前
Android第三次面试总结之网络篇补充
android·网络·面试
Yvonne爱编码44 分钟前
CSS- 4.4 固定定位(fixed)& 咖啡售卖官网实例
前端·css·html·状态模式·hbuilder
SuperherRo1 小时前
Web开发-JavaEE应用&SpringBoot栈&SnakeYaml反序列化链&JAR&WAR&构建打包
前端·java-ee·jar·反序列化·war·snakeyaml
大帅不是我1 小时前
Python多进程编程执行任务
java·前端·python
前端怎么个事1 小时前
框架的源码理解——V3中的ref和reactive
前端·javascript·vue.js
Ciito1 小时前
将 Element UI 表格元素导出为 Excel 文件(处理了多级表头和固定列导出的问题)
前端·vue.js·elementui·excel
不爱吃饭爱吃菜2 小时前
uniapp微信小程序一键授权登录
前端·javascript·vue.js·微信小程序·uni-app
heart000_12 小时前
从零开始打造个人主页:HTML/CSS/JS实战教程
javascript·css·html