详解instanceof底层原理,从零手写一个instanceof

壹 ❀ 引
本道题的核心考点还是对于javascript
原型的掌握程度,比如__proto__
,prototype
相关概念,以及instanceof
底层原理的理解。若你对于原型已经非常熟悉,那么可以直接开始阅读,以及在看完instanceof
原理后可以尝试自己先手写。若不太熟悉,强烈建议先阅读博主关于原型的博文,不然原型链这点可能会把你绕晕。
蛋生鸡鸡生蛋的哲学探讨,Javascript中Function与Object究竟谁出现的更早?
那么请跟随我的思路,本文开始。
贰 ❀ instanceof底层查找原理
要想实现一个东西,我们总得先知道它是个啥东西,先从基本概念说起,instanceof
运算符语法如下:
object instanceof constructor
其中,object
表示某个实例对象,constructor
表示某个构造函数。它的作用是用于检查constructor.prototype
是否存在于参数object
的原型链上。
翻译直白一点,假设我们是A instanceof B
,那么就是看B
的原型,是否出现在A
的原型链上。
我们来通过几个例子加深这段概念的理解:
function Person(name) {
this.name = name;
};
Person.prototype.sayName = function () {
return this.name
};
const p = new Person('听风是风');
p.sayName(); // 听风是风
此时用instanceof
来检验:
p instanceof Person; // true
为什么为true
,用概念来解释,Person
的原型也就是Person.prototype
,它直接等于p.__proto__
,既然都相等,那自然有出现在p
的原型上,所以上述代码等同于:
p.__proto__ === Person.prototype;// true
考虑到有同学可能忘记了原型相关的概念,简单复习下,javascript
中,除了undefined
与null
之外的万物皆为对象,不管你是字符串,数组,都会有__proto__
属性指向创建自己的构造函数的原型,也就是prototype
。所以上述例子实例p
的__proto__
指向创建自己的构造函数Person.prototype
,既然相当,那instanceof
为true
合情合理。
来看第二个例子:
p instanceof Object;// true
还是上面的例子,只是此时我们判断Object.prototype
有没有出现在实例p
的原型链上,要解释这个问题,我们就得明白原型链的意思。
还记得上面p.sayName()
调用吗?p
自身其实并没有这个方法,但能成功调用,这是因为p
能通过p.__proto__
访问到构造函数的原型,从而使用到这个方法,那假设Person.prototype
也没有呢?由于原型prototype
本质就是一个对象,既然你是对象,那么原型肯定也有自己的__proto__
,用于指向创建自己的构造器的原型,而这个查找过程就形成了一个链,当然原型链也是有顶点的也就是是null
,而这个查找的过程也就是所谓的原型链了。
解释了原型链,我们来看看Person.prototype
的__proto__
是谁,如下图:

这里的[[Prototype]]
其实就是我们所说的__proto__
,它指向了创建自己的构造器的原型,所以也是个对象,而原型prototype
上都会有一个constructor
属性,这个玩意可以理解为原型的标识,用于标识它是哪个构造器的原型,如上图,很明显这个构造器就是Object
了。
所以上面的instanceof
本质上等同于:
// p.__proto__ 找到了Person的原型
// 原型也是个对象,p.__proto__.__proto__又找到了Object的原型
p.__proto__.__proto__ === Object.prototype;// true
而关于我们所说的原型链顶端是null
的问题,因为你一个原型链不可能像死循环一样没有终点,只要你是{}
这种对象类型,创建你们的造世主都是构造器Object()
,所以这种对象都能访问到Object.prototype
,我们都说Object
是普通对象的造世主了,它的原型很显然没办法再往上找,终点就被设置为null
了,具体可见下图。

叁 ❀ 手写instanceof
我们在上面花了较大的篇幅用来解释instanceof
的含义以及底层查找过程,毕竟知道了原型我们才知道如何去手写实现它。说到底,以A instanceof B
为例,本质做的就是看递归A
的原型链,不断的.__proto__
一层层网上找一直找到null
为止,看看有没有某一处的.__proto__
等于B.prototype
,如果有就返回true
,找到null
了都不相等那就返回false
,既然知道了原理,一个递归搞定,实现如下:
const instanceof_ = (A, B) => {
// 前置判断,不符合直接访问false
if (typeof A !== 'object' || A === null || typeof B !== 'function') {
return false;
};
const prototype = B.prototype;
let __proto__ = A.__proto__;
while (true) {
// 假设找到顶端了,返回false
if (__proto__ === null) {
return false;
};
// 假设相等,返回true
if (prototype === __proto__) {
return true;
};
// 一直顺着__proto__往上找
__proto__ = __proto__.__proto__;
}
}
console.log(instanceof_(p, Person)); // true
console.log(instanceof_(1, Number)); // false
console.log(instanceof_(new Number(1), Number)); // true
有同学可能不理解这个函数内部的前置条件为什么这么写,这里我再解释下,当然如果你原型的理解非常透彻,这部分解释就可以直接跳过了。
根据语法A instanceof B
,我们可以得知两点,首先A
得是一个实例对象,B
得是一个构造器函数。
为什么这么说?因为在javascript
中只有函数才有prototype
属性,函数是一等公民,老大哥,这就是它的特殊之处,因此只要B
不是函数类型,那就不用判断了,我这里是直接返回了false
,你其实可以抛错,这里我们就不拘小节了。
那为什么我们说A
应该是个对象呢?看下面这个例子:
1 instanceof Number;// false
new Number(1) onstanceof Number;// true
其实语法我们就知道了,A
一定得是个对象,上面例子1
很明显不算是一个标准的对象,它算是一个包装对象,因为不算是数字还是字符串,它们也有__proto__
属性,不然数字字符串上的方法哪来的,它们本质还是对象,关于这点可以阅读博主关于原型的博客,里面有解释。
1..__proto__ === Number.prototype;// true
'听风是风'.__proto__ === String.prototype;// true
我们实现instanceof
原理就是判断__proto__
与构造器原型是否相等,很明显如果这样写但不对基本类型做判断,返回的结果就与原生instanceof
不一致了,因此才做了typeof A !== 'object'
的限制,而typeof null === 'object'
算是javascript
中公认的设计缺陷了,因此就加了不等于null
的判断了。
肆 ❀ 总
你看,说是实现一个instanceof
,本质上考核的还是对于原型概念的理解,如果你之前对于原型掌握的非常熟悉,我相信本文阅读下来你会非常的流程,毕竟博主自己写下来就是行云流水 = =,原型这块可是老熟了,好了,本文就到这里结束了。
详解instanceof底层原理,从零手写一个instanceof的更多相关文章
- 分布式大牛详解Zookeeper底层原理
很多学员都在反馈,说zk很难学,学的不是很明白,在这里,我继续带着大家详解一遍Zookeeper 首先zk是什么呢首先肯定是一个个分布式服务框架,是Apache Hadoop 的一个子项目,它主要是用 ...
- “makefile”写法详解,一步一步写一个实用的makefile,详解 sed 's,$∗\.o[ :]*,\1.o $@ : ,g' < $@.
目的:编写一个实用的makefile,能自动编译当前目录下所有.c/.cpp源文件,支持二者混合编译.并且当某个.c/.cpp..h或依赖的源文件被修改后,仅重编涉及到的源文件,未涉及的不编译. 二要 ...
- Java 详解 JVM 工作原理和流程
Java 详解 JVM 工作原理和流程 作为一名Java使用者,掌握JVM的体系结构也是必须的.说起Java,人们首先想到的是Java编程语言,然而事实上,Java是一种技术,它由四方面组成:Java ...
- TCP/IP详解学习笔记 这位仁兄写得太好了.(转载)
TCP/IP详解学习笔记 这位仁兄写得太好了 TCP/IP详解学习笔记 这位仁兄写得太好了. http://blog.csdn.net/goodboy1881/category/20444 ...
- Block详解二(底层分析)
Block专辑: Block讲解一 MRC-block与ARC-block Block详解一(底层分析) 今天讲述Block的最后一篇,后两篇仅仅是加深1,2篇的理解,废话少说,开始讲解! __blo ...
- 深入解析ThreadLocal 详解、实现原理、使用场景方法以及内存泄漏防范 多线程中篇(十七)
简介 从名称看,ThreadLocal 也就是thread和local的组合,也就是一个thread有一个local的变量副本 ThreadLocal提供了线程的本地副本,也就是说每个线程将会拥有一个 ...
- linux dd命令参数及用法详解---用指定大小的块拷贝一个文件(也可整盘备份)
linux dd命令参数及用法详解---用指定大小的块拷贝一个文件 日期:2010-06-14 点击:3830 来源: 未知 分享至: linux dd命令使用详解 dd 的主要 ...
- TCP/IP详解学习笔记 这位仁兄写得太好了
TCP/IP详解学习笔记(1)-基本概念 为什么会有TCP/IP协议 在世界上各地,各种各样的电脑运行着各自不同的操作系统为大家服务,这些电脑在表达同一种信息的时候所使用的方法是千差万别.就好像圣 ...
- 初级游戏外挂编程详解 windows运行原理+游戏辅助编程 游戏外挂编程
详解游戏辅助编程 [目录] 1-什么是Windows API 2-Windows进程 3-Windows 的内存的运行原理 4-windows 中句柄的概念 5-Windows的变量类型 6-辅助实现 ...
- Linux : select()详解 和 实现原理【转】
转自:http://blog.csdn.net/huntinux/article/details/39289317 原文:http://blog.csdn.net/boboiask/article/d ...
随机推荐
- 基于java+springboot的图书借阅网站-在线图书借阅管理系统
该系统是基于java+springboot开发的图书借阅管理系统.是给师弟开发的课程作业.大家学习过程中,遇到问题可以github咨询作者. 系统演示地址 前台 http://book.gitapp. ...
- Pgsql之查询一段时间内的所有日期
前几天干活儿的时候,项目中有这么个需求,需要用pgsql查询两个日期间的所有日期,包括年月日,下面贴代码: 1 select date(t) as day 2 from 3 generate_seri ...
- 【SHELL】反斜杠解决多个shell实例扩展
本意是想获取代码仓相对路径,代码如下 base_dir=`pwd` repo forall -c '{ user_dir=$(realpath --relative-to="$bas ...
- 百度网盘(百度云)SVIP超级会员共享账号每日更新(2023.11.30)
一.百度网盘SVIP超级会员共享账号 可能很多人不懂这个共享账号是什么意思,小编在这里给大家做一下解答. 我们多知道百度网盘很大的用处就是类似U盘,不同的人把文件上传到百度网盘,别人可以直接下载,避免 ...
- [转帖]Shell三剑客之sed
目录 Shell三剑客 sed工具 sed 流编辑器的工作过程 sed命令格式与选项操作符 sed命令的常用选项 sed命令的打印功能 默认打印方式 sed命令的寻址打印 文本模式过滤行内容 sed的 ...
- [转帖] Jmeter学习笔记(七)——监听器元件之察看结果树
https://www.cnblogs.com/pachongshangdexuebi/p/11507289.html 在jmeter中,如果我们需要查看请求结果就需要添加查看结果树,这个监听器元件有 ...
- [转帖]如何在 Linux 中使用ss命令监控网络连接
https://zhuanlan.zhihu.com/p/99421574 ss命令是用于在Linux系统上显示与网络套接字相关的信息的工具. 该工具显示netstat命令的更多详细信息,该命令用于显 ...
- 微软Windows Sever系统也将强制要求TPM及CPU兼容
https://www.cnbeta.com/articles/tech/1238647.htm 去年微软推出Win11系统时,TPM安全模块以及Intel 8代酷睿/AMD锐龙2代及以上的硬件要求引 ...
- 【我在京东做研发】揭秘支撑京东万人规模技术人员协作的行云DevOps平台
分享人:孙长虹 京东云DevOps解决方案架构师 复旦大学计算机系毕业,并拥有人民大学心理学硕士学位.曾任职于Alcatel-Lucent,IBM和惠普,具有丰富的大型复杂产品研发及项目管理经验,擅长 ...
- 【VictoriaMetrics源码阅读】: vm中对map的优化
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu github 公众号:一本正经的瞎扯 具体代码请看:https://github.com/ahf ...