探讨 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运算符不能用于检测基本数据类型,只能用于检测对象是否属于某个类或构造函数。

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

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

相关推荐
2401_8791036841 分钟前
24.11.10 css
前端·css
ComPDFKit2 小时前
使用 PDF API 合并 PDF 文件
前端·javascript·macos
yqcoder2 小时前
react 中 memo 模块作用
前端·javascript·react.js
谈谈叭2 小时前
Javascript中的深浅拷贝以及实现方法
开发语言·javascript·ecmascript
优雅永不过时·3 小时前
Three.js 原生 实现 react-three-fiber drei 的 磨砂反射的效果
前端·javascript·react.js·webgl·threejs·three
爱编程的鱼3 小时前
javascript用来干嘛的?赋予网站灵魂的语言
开发语言·javascript·ecmascript
神夜大侠5 小时前
VUE 实现公告无缝循环滚动
前端·javascript·vue.js
明辉光焱5 小时前
【Electron】Electron Forge如何支持Element plus?
前端·javascript·vue.js·electron·node.js
柯南二号6 小时前
HarmonyOS ArkTS 下拉列表组件
前端·javascript·数据库·harmonyos·arkts
wyy72936 小时前
v-html 富文本中图片使用element-ui image-viewer组件实现预览,并且阻止滚动条
前端·ui·html