类型的判断可以说在我们前端开发过程中无处不在,特别是在Typescript还未推出之前,我们在JS里面做类型判断显得就更加重要了。
判断数据类型的方式有特别多,比如大家常用的typeof、instanceof、Object.prototype.tostring.call()等等,那么每一种判断数据类的方法大家知道其中的原理吗?比如说instanceof的原理,今天我们就聊一聊instanceof是如何判断数据类型的。
1.基本概念想要了解instanceof的原理,我们至少应该知道它的基本概念吧,我们可以先来看看官网是如何解释它的。
官网解释:
instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上。
虽然官方的解释只有简短的一句话,但是对于许多人来说还是挺难理解的,不过我们可以抓出这句话中的几个关键点:
运算符
构造函数的prototype
对象原型链
很明显,instanceof与原型和原型链有关,所以强烈建议小伙伴们先去学一学原型和原型链的相关知识。
为了让小伙伴现有一个大概理解,我们用我们自己的话简单说一下instance。
通俗的解释:
instanceof是一个运算符,它可以用来判断某一个对象的类型,具体原理就是利用了原型和原型链。
基本用法:
AinstanceofB//trueorfalse上段代码中的A就是我们需要判断类型的对象,B就是官方所说的构造函数,形如我们的Object、Function都可以称之为构造函数。
2.与typeof对比我们判断类型的时候通常是将typeof和instanceof结合使用,虽然它们都可以判断数据类型,但是它们还是有很多不同点的,如下:
typeof:主要用来判断基础数据类型,比如:Number、String等等。
instanceof:主要用来判断对象数据类型,比如Function、Array等等。
typeof直接返回数据类型,而instanceof重在判断,它返回布尔值。
我们来看一段代码大家可能会更好理解一些。
代码如下:
<script>functionsay(){};//typeof判断数据类型console.log(typeof'小猪课堂');//stringconsole.log(typeof100);//numberconsole.log(typeoftrue);//booleanconsole.log(typeofundefined);//undefinedconsole.log(typeof{});//objectconsole.log(typeof[]);//objectconsole.log(typeofnull);//objectconsole.log(typeofsay);//function//instanceof判断数据类型leta=newString('123');letb=newsay();console.log('123'instanceofString);//falseconsole.log(ainstanceofString);//trueconsole.log([]instanceofArray);//trueconsole.log(binstanceofsay);//true</script>从上段代码我们可以看出typeof只能判断基础数据类型(null除外),当判断其它数据类型时,它总是返回object或者function。
而instanceof可以用来判断对象数据类型,返回的是布尔值。
3.instanceof特点上节中有一段代码我们可以拿出来再看一看:
letb=newsay();console.log(binstanceofsay);//true上段代码中b是实例对象,say是构造函数,我们利用instanceof来进行判断时,返回的true,由此我们可以总结出instanceof如下特点:
instanceof左侧是一个实例对象,右侧是一个构造函数。
如果实例对象属于构造函数,那么instanceof就会返回true。
我们判断类型是使用的Array、Object、String等等其实就是一个构造函数。
总结:
由上可以得出,判断数据类型并不是instanceof最准确的说法,它主要是用来判断实例对象与构造函数之间的关系的。而判断数据类型只是我们利用它的特点变相实现罢了。
4.instanceof原理到这里我们知道instanceof其实不仅仅是用来判断数据类型的,它实际上是用来判断一个实例对象与一个构造函数之间的关系的。
那么我们通常如何判断一个实例对象与一个构造函数之间的关系的呢?
答案就是利用原型和原型链!我们都知道每一个函数都有一个显式原型prototype,每一个对象都有一个隐式原型__proto__,当我们对象的原型链中存在构造函数的显式原型prototype时,我们就可以确定它们之间时存在关系的。
更简单的说法:
我们拿到instanceof左侧对象的原型链
再拿到instanceof右侧构造函数的显式原型prototype
如果原型链中存在显式原型prototype,instanceof返回true,否则返回false
如果大家对上面的说明看的模糊,那么快去补一补原型和原型链的知识。
我们可以简单实现一个instanceof函数,大家就更容易理解了。
代码如下:
/***@description判断对象是否属于某个构造函数*@pramsleft:实例对象right:构造函数*@returnboolean*/functionmyInstanceof(left,right){letrightPrototype=right.prototype;//获取构造函数的显式原型letleftProto=left.__proto__;//获取实例对象的隐式原型while(true){//说明到原型链顶端,还未找到,返回falseif(leftProto===null){returnfalse;}//隐式原型与显式原型相等if(leftProto===rightPrototype){returntrue;}//获取隐式原型的隐式原型,重新赋值给leftProtoleftProto=leftProto.__proto__}}代码比较简单,主要就是需要循环实例对象的原型链。
我们回过头再看一遍代码:
letb=newsay();console.log(binstanceofsay);//true上段代码为什么会返回true呢,其实是因为在new的操作过程中,有一步操作便是将say()构造函数的显式原型prototype赋值给了b的隐式原型__proto__,所以我们利用instance判断时,必然会满足leftProto===rightPrototype条件。
至于new操作符具体做了什么,大家可以去参考我的另一篇文章。
大家也可以直接打印看看结果:
console.log(b.__proto__===say.prototype);//true5.补充instanceof判断数组时,如果把它归纳为Array是返回true,如果把它归纳为Object也是返回true的。
代码如下:
letarray=[1,2,3]console.log(arrayinstanceofArray);//trueconsole.log(arrayinstanceofObject);//true究其原因其实是我们的数组也是一个对象,只不过这个对象稍微特殊一点罢了,大家也可以把数组的原型打印出来看看,一下就会明白了。
总结看到这儿,你再回过头去看看官网关于instanceof的解释,相信你会恍然大悟!
instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上。
如果觉得文章太繁琐或者没看懂,可以观看视频:?小猪课堂
原文:https://juejin.cn/post/7103335306103324685logo设计
创造品牌价值
¥500元起
APP开发
量身定制,源码交付
¥2000元起
商标注册
一个好品牌从商标开始
¥1480元起
公司注册
注册公司全程代办
¥0元起
查
看
更
多
一文搞懂instanceof实现的原理是什么!
instanceof是一个运算符,它可以用来判断某一个对象的类型,具体原理就是利用了原型和原型链。基本用法:AinstanceofB\/\/trueorfalse 上段代码中的A就是我们需要判断类型的对象,B就是官方所说的构造函数,形如我们的Object、Function都可以称之为构造函数。2.与typeof对比我们判断类型的时候通常是将typeo...
中级微观:一文搞懂希克斯分解及举例
一、希克斯分解的精髓希克斯分解的核心在于,它在效用保持不变的前提下,揭示了商品价格变动如何影响购买量。让我们通过一个生动的场景来说明:想象消费者预算线在商品X价格下降时的动态调整。首先,预算线在无差异曲线U1上保持切点不变,然后平行移动,接着保持斜率,直到与新预算线重合。这个过程中的变动...
一文搞懂Linux内核内存管理中的KASAN实现原理
在实践中,KASAN在Linux内核4.18版本中表现出色,通过检测slab-out-of-bounds错误,为内存管理提供了强大的安全保障。深入理解KASAN的工作原理,对保证系统稳定性和代码质量至关重要。
一文搞懂反向传播算法
变量就是下文要介绍的delta变量,一来简化公式,二来减少计算量,有点动态规划的赶脚。 下来用事实说话,大家仔细观察一下在第四部分链式求导部分误差对于输出层的w11以及隐藏层的w11求偏导以及偏置的求偏导的过程,你会发现,三个公式存在相同的部分,同时隐藏层参数求偏导的过程会用到输出层参数求偏导的部分公式,这正...
一文搞懂设计模式--模板模式
我们先看初学者的简单实现:程序输出:小明出门了 小明骑上自行车 小明从大厅进入公司 然而,当需求增加时,新代码不断涌现,这使得代码难以维护。接下来,我们将运用模板模式,将问题简化。模板模式实际上是在父类中定义处理流程框架,在子类中具体实现不同处理。场景中的步骤可抽象为三个方法,父类提供...
内存管理(六):一文搞懂malloc、free实现原理
malloc 的实现方式一:显式空闲链表 + 整块分配 缺点是每次分配都需要从头到尾遍历,采用首次适应法,内存块会被整体分配,容易产生较多内部碎片。malloc 的实现方式二:显式空闲链表 + 按需分配 优点是分配和释放只需要在链表头进行操作,都是常数时间,节省空间,缺点是容易产生外部碎片。malloc 的实现...
DNS是什么?一文彻底搞懂DNS的原理机制
而动态解析则通过专用的域名服务器提供域名与IP地址的映射关系。DNS代理是一种网络组件,允许客户端将DNS请求直接发送给代理服务器,代理服务器负责查询DNS服务器并返回结果给客户端,从而简化网络管理,减少配置工作。DNS系统通过上述机制,实现了高效、可靠的域名解析,为网络通信提供了基础支持。
一文搞懂异步、并发、协程原理
IO多路复用技术,就像一个优秀的指挥,让舞者们避免无谓的等待,提高效率。并发与并行:逻辑与物理的交响并发如同多个舞者在同一时间段内各自演绎,可以是多进程、多线程或协程,各自独立的旋律。而并行则是物理层面的同步,所有舞者在同一时刻共舞,但实际操作复杂,不易实现。从C++协程到学习资源:探索之旅...
一文彻底搞懂CAS实现原理 & 深入到CPU指令
本文深入解析 CAS 实现原理及 CPU 指令,旨在帮助读者理解并发编程中的核心概念。在并发操作中,CAS(Compare And Swap)是一种乐观锁机制,用于保障线程安全。它通过比较并交换共享变量的当前值与期望值,来实现原子操作,确保并发环境下的正确性。具体而言,CAS 机制在多个线程同时操作共享资源时,仅允许...
Webpack原理系列之彻底搞懂loader原理
上面的代码,我们通过this调用了async方法,获取一个callback,这种方式可以让我们在Loader中实现异步操作。 什么是loader上下文呢,简单来讲就是this,loader的this上有许多变量和函数,能方便我们获取当前需要处理的文件,或者异步处理文件内容。原理也很简单,就是通过apply来实现function?loader(source)?{???let?script?=?