墨魇博客 墨魇博客
  • 注册
  • 登录
  • 首页
  • 分类
    • Linux
    • Python
    • WEB前端
    • PHP
    • SEO
    • Mysql
  • 资源
    • 源码
    • 素材
  • 碎碎念
  • 音乐
  • 专题
  • 留言板
首页 › WEB前端 › 浅谈 instanceof 和 typeof 的实现原理

浅谈 instanceof 和 typeof 的实现原理

墨魇
10月 8, 2018发布在 WEB前端
1,951 0 1

浅谈 instanceof 和 typeof 的实现原理-墨魇博客

typeof 实现原理

typeof 一般被用于判断一个变量的类型,我们可以利用 typeof 来判断number, string, object, boolean, function, undefined, symbol 这七种类型,这种判断能帮助我们搞定一些问题,比如在判断不是 object 类型的数据的时候,typeof能比较清楚的告诉我们具体是哪一类的类型。但是,很遗憾的一点是,t**ypeof 在判断一个 object的数据的时候只能告诉我们这个数据是 object, 而不能细致的具体到是哪一种 object**

let s = new String('abc');typeof s === 'object'// trues instanceof String // true

要想判断一个数据具体是哪一种 object 的时候,我们需要利用 instanceof 这个操作符来判断,这个我们后面会说到。
来谈谈关于 typeof 的原理吧,我们可以先想一个很有意思的问题,js 在底层是怎么存储数据的类型信息呢?或者说,一个 js 的变量,在它的底层实现中,它的类型信息是怎么实现的呢?
其实,++js 在底层存储变量的时候,会在变量的机器码的低位1-3位存储其类型信息++
– 000:对象
– 010:浮点数
– 100:字符串
– 110:布尔
– 1:整数

but, 对于 undefined 和 null 来说,这两个值的信息存储是有点特殊的。

null:所有机器码均为0
undefined:用 −2^30 整数来表示
所以,typeof 在判断 null 的时候就出现问题了,由于 null 的所有机器码均为0,因此直接被当做了对象来看待。
然而用 instanceof 来判断的话

1.null instanceof null // TypeError: Right-hand side of 'instanceof' is not an object

null 直接被判断为不是 object,这也是 JavaScript 的历史遗留bug,可以参考typeof。

因此在用 typeof 来判断变量类型的时候,我们需要注意,最好是用 typeof 来判断基本数据类型(包括symbol),避免对 null 的判断。

还有一个不错的判断类型的方法,就是Object.prototype.toString,我们可以利用这个方法来对一个变量的类型来进行比较准确的判断

Object.prototype.toString.call(1) // "[object Number]"Object.prototype.toString.call('hi') // "[object String]"Object.prototype.toString.call({a:'hi'}) // "[object Object]"Object.prototype.toString.call([1,'a']) // "[object Array]"Object.prototype.toString.call(true) // "[object Boolean]"Object.prototype.toString.call(() => {}) // "[object Function]"Object.prototype.toString.call(null) // "[object Null]"Object.prototype.toString.call(undefined) // "[object Undefined]"Object.prototype.toString.call(Symbol(1)) // "[object Symbol]"

instanceof 操作符的实现原理

之前我们提到了 instanceof 来判断对象的具体类型,其实 instanceof 主要的作用就是判断一个实例是否属于某种类型

let person = function () {}let nicole = new person()nicole instanceof person // true

当然,instanceof 也可以判断一个实例是否是其父类型或者祖先类型的实例。

let person = function () {}let programmer = function () {}programmer.prototype = new person()let nicole = new programmer()nicole instanceof person // truenicole instanceof programmer // true

这是 instanceof 的用法,但是 instanceof 的原理是什么呢?根据 ECMAScript 语言规范,我梳理了一下大概的思路,然后整理了一段代码如下

function new_instance_of(leftVaule, rightVaule) { let rightProto = rightVaule.prototype; // 取右表达式的 prototype 值 leftVaule = leftVaule.__proto__; // 取左表达式的__proto__值 while (true) { if (leftVaule === null) { return false; } if (leftVaule === rightProto) { return true; } leftVaule = leftVaule.__proto__ }}

其实 instanceof 主要的实现原理就是只要右边变量的 prototype 在左边变量的原型链上即可。因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果查找失败,则会返回 false,告诉我们左边变量并非是右边变量的实例。
看几个很有趣的例子

function Foo() {}Object instanceof Object // trueFunction instanceof Function // trueFunction instanceof Object // trueFoo instanceof Foo // falseFoo instanceof Object // trueFoo instanceof Function // true

要想全部理解 instanceof 的原理,除了我们刚刚提到的实现原理,我们还需要知道 JavaScript 的原型继承原理。

关于原型继承的原理,我简单用一张图来表示

浅谈 instanceof 和 typeof 的实现原理-墨魇博客

我们知道每个 JavaScript 对象均有一个隐式的 proto 原型属性,而显式的原型属性是 prototype,只有 Object.prototype.proto 属性在未修改的情况下为 null 值。根据图上的原理,我们来梳理上面提到的几个有趣的 instanceof 使用的例子。
– Object instanceof Object
– 由图可知,Object 的 prototype 属性是 Object.prototype, 而由于 Object 本身是一个函数,由 Function 所创建,所以 Object.proto 的值是 Function.prototype,而 Function.prototype 的 proto 属性是 Object.prototype,所以我们可以判断出,Object instanceof Object 的结果是 true 。用代码简单的表示一下

leftValue = Object.__proto__ = Function.prototype;rightValue = Object.prototype;// 第一次判断leftValue != rightValueleftValue = Function.prototype.__proto__ = Object.prototype// 第二次判断leftValue === rightValue// 返回 true

Function instanceof Function 和 Function instanceof Object 的运行过程与 Object instanceof Object 类似,故不再详说。

  • Foo instanceof Foo
    • Foo 函数的 prototype 属性是 Foo.prototype,而 Foo 的 proto 属性是 Function.prototype,由图可知,Foo 的原型链上并没有 Foo.prototype ,因此 Foo instanceof Foo 也就返回 false 。
leftValue = Foo, rightValue = FooleftValue = Foo.__proto = Function.prototyperightValue = Foo.prototype// 第一次判断leftValue != rightValueleftValue = Function.prototype.__proto__ = Object.prototype// 第二次判断leftValue != rightValueleftValue = Object.prototype = null// 第三次判断leftValue === null// 返回 false
  • Foo instanceof Object
leftValue = Foo, rightValue = ObjectleftValue = Foo.__proto__ = Function.prototyperightValue = Object.prototype// 第一次判断leftValue != rightValueleftValue = Function.prototype.__proto__ = Object.prototype// 第二次判断leftValue === rightValue// 返回 true 
  • Foo instanceof Function
leftValue = Foo, rightValue = FunctionleftValue = Foo.__proto__ = Function.prototyperightValue = Function.prototype// 第一次判断leftValue === rightValue// 返回 true 

总结

简单来说,我们使用 typeof 来判断基本数据类型是 ok 的,不过需要注意当用 typeof 来判断 null 类型时的问题,如果想要判断一个对象的具体类型可以考虑用 instanceof,但是 instanceof 也可能判断不准确,比如一个数组,他可以被 instanceof 判断为 Object。所以我们要想比较准确的判断对象实例的类型时,可以采取 Object.prototype.toString.call 方法。

1
mysql, mariaDB 分库分表设计草案及相关笔记
上一篇
Linux常用基本命令
下一篇
评论 (0)
再想想
贴标签
HTMLJavaScriptjsLinuxMariaDBMySQLPHPPHP数组PythonSEOSQLswooleswoole +thinkPHP5thinkPHP5墨魇墨魇SEO墨魇个人博客心情记程序员随笔
1
相关文章
带你走进 WebGL 中的图形噪声随机美学
JavaScript反调试技巧
JavaScript错误处指南
ui2code中的深度学习+传统算法应用

他那时还太年轻,不懂所有命运馈赠的礼物早已在暗中标好了价格

HomePHPSQLPythonLinuxSEOHTML碎碎念音乐留言小伙伴
钟华博客 松鼠乐园
Copyright © 2016-2021 墨魇博客. Designed by 墨魇. 黔ICP备17010868号
未登录
现在登录 / 注册,享受更多福利
  • Home
  • PHP
  • SQL
  • Python
  • Linux
  • SEO
  • HTML
  • 碎碎念
  • 音乐
  • 留言
  • 小伙伴
热门搜索
  • 随笔
  • 心情记
  • 墨魇个人博客
  • Python
  • PHP
  • 墨魇
  • 程序员
  • Linux
  • MySQL
  • HTML
  • SEO
  • 墨魇SEO
  • SQL
  • js
  • swoole
  • thinkPHP5
  • swoole +thinkPHP5
  • PHP数组
墨魇
作为一个出色的精神病患者,我的理想是至少要杀死一个奥特曼
115 文章
33 评论
163 喜欢
  • 1
  • 0
  • Top