探讨 instanceof 的实现原理,并尝试手写

深入探讨 instanceof 运算符的实现原理

JavaScript 中的 instanceof 运算符是一种用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上的工具。在最后,我们将一起深入探讨 instanceof 的原理,并且通过手写代码实现一个简单版本的 myInstanceof例子。

1. instanceof 运算符的基本原理

1. 介绍

instanceof提供了一种简便的方式来验证对象的类型,但要真正理解它,我们需要深入探讨 JavaScript 的原型链,如果你不认识原型链就先阅读一下这篇文章吧:当你被面试问到:你还记得原型和原型链吗?

2. JavaScript 的原型链

我们在这里简单概述一下原型链:

在 JavaScript 中,每个对象都有一个指向其原型的引用。原型是一个对象,它包含共享属性和方法,可以被其他对象继承。这种原型链的结构允许对象在没有显式定义类或接口的情况下实现继承。

3. instanceof 运算符的原理

复杂来说:

在JavaScript中,每个对象都有一个内部属性[[Class]],用于表示它的类型。这个属性是由ECMAScript规范定义的,并且不能被直接访问或修改。但是,我们可以通过一些手段来间接地获取一个对象的[[Class]]属性,从而实现instanceof运算符。

我们来看一个简单的示例:

javascript 复制代码
var arr = [1, 2, 3];  
console.log(arr instanceof Array); // true  
console.log(arr instanceof Object); // true  

在这个例子中,我们使用instanceof运算符来检测arr是否属于ArrayObject类。由于数组Object的一个子类,因此arr数组同时也属于Object类。因此,上面的两个console.log语句都会输出true

所以,我们还需要了解JavaScript中的构造函数构造函数是一种特殊的函数,用于创建新的对象。在JavaScript中,函数也是一种对象,因此它们也有一个[[Class]]属性。ECMAScript规范定义了一些内置的构造函数,比如ArrayObjectFunction等。

当我们使用new运算符来调用一个构造函数时,JavaScript会创建一个新的对象,并将该对象的[[Class]]属性设置为构造函数的名称。同时,JavaScript还会将该对象的原型指向构造函数prototype属性。这样,我们就可以通过原型链来访问构造函数中定义的方法和属性。

复杂的不太好理解,我们直接上简单:

实际上,instanceof运算符的实现原理非常简单。它通过检查对象的原型链来确定对象是否属于某个类或构造函数。instanceof 运算符的核心原理是基于原型链的查找。当我们使用 obj instanceof Constructor 进行判断时,JavaScript 引擎会从 obj 的原型链上查找 Constructor.prototype 是否存在。如果存在,则返回 true,否则继续在原型链上查找。如果查找到原型链的顶端仍然没有找到,返回 false

其实就是这样的三个小步骤:

  • 对象通过 Object.getPrototypeOf(obj) 获取其原型。
  • 检查对象的原型是否与目标构造函数的原型相等。
  • 如果相等,返回 true;否则,沿着原型链继续查找,直到找到匹配的原型或到达原型链的末尾返回false

但是需要注意哦,instanceof 运算符只能用于检查某个对象是否是某个构造函数的实例,不能用于基本类型的检查,如字符串、数字等。

2. 手写代码实现 myInstanceof

现在,我们已经基本了解了它,让我们根据三个小步骤来手写一个简单版本的 myInstanceof 函数,以更好地理解其实现原理吧:

javascript 复制代码
function myInstanceof(obj, constructor) {
    if (obj === null || typeof obj !== 'object') { // 注意不能用于基本类型的检查,如字符串、数字等,直接false。
        return false;
    }

    let proto = Object.getPrototypeOf(obj); // 获取其原型

    while (proto !== null) { // 如果原型存在
        if (proto === constructor.prototype) { //检查对象的原型是否与目标构造函数的原型相等。
            return true;
        }
        proto = Object.getPrototypeOf(proto); // 沿着原型链查找
    }

    return false; // 到达原型链末尾也没找到返回false
}

// 测试示例
function Animal() {}
function Dog() {}
Dog.prototype = new Animal();

const myDog = new Dog();

console.log(myInstanceof(myDog, Dog));   // true
console.log(myInstanceof(myDog, Animal)); // true
console.log(myInstanceof(myDog, Object)); // true
console.log(myInstanceof(myDog, Array));  // false

在这个简单的实现中,我们首先要检查参数的合法性,确保传入的第一个参数是一个对象,我们只能用来检查对象。然后,我们获取了对象的原型,并沿着原型链一直向上查找,看是否能找到目标构造函数的 prototype。如果找到了的话,就返回 true;如果遍历完整个原型链都没有找到,则返回 false

3. 总结

总结来说,instanceof运算符的实现原理非常简单,它通过检查对象的原型链来确定对象是否属于某个类或构造函数。在实际开发中,我们可以使用自定义函数来模拟instanceof运算符的功能,从而更好地理解它的背后机制。同时,我们需要注意instanceof运算符不能用于检测基本数据类型,只能用于检测对象是否属于某个类或构造函数。

那么我们这篇文章到这里就结束啦~

如果你想了解更多这类文章,点赞关注作者更新更多后续~

相关推荐
爱上妖精的尾巴1 天前
8-5 WPS JS宏 match、search、replace、split支持正则表达式的字符串函数
开发语言·前端·javascript·wps·jsa
小温冲冲1 天前
通俗且全面精讲单例设计模式
开发语言·javascript·设计模式
Remember_9931 天前
MySQL 索引详解:从原理到实战优化
java·数据库·mysql·spring·http·adb·面试
❀͜͡傀儡师1 天前
基于大语言模型的简历分析和模拟面试系统
人工智能·语言模型·面试
Warren981 天前
Pytest Fixture 作用域与接口测试 Token 污染问题实战解析
功能测试·面试·单元测试·集成测试·pytest·postman·模块测试
意法半导体STM321 天前
【官方原创】FDCAN数据段波特率增加后发送失败的问题分析 LAT1617
javascript·网络·stm32·单片机·嵌入式硬件·安全
为什么不问问神奇的海螺呢丶1 天前
n9e categraf redis监控配置
前端·redis·bootstrap
云飞云共享云桌面1 天前
推荐一些适合10个SolidWorks设计共享算力的服务器硬件配置
运维·服务器·前端·数据库·人工智能
June bug1 天前
软件测试面试常见问答题2
面试·职场和发展
咔咔一顿操作1 天前
轻量无依赖!autoviwe 页面自适应组件实战:从安装到源码深度解析
javascript·arcgis·npm·css3·html5