0%

typeof、instanceof

知道js方法的实现原理,我们就能更好的使用它,知道为什么有这样的结果

关于typeof、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
2
null instanceof null 
// TypeError: Right-hand side of 'instanceof' is not an object

null 直接被判断为不是 object,这也是 JavaScript 的历史遗留bug

typeof 的安全防范机制

首先,我们得知道undefined和undeclared的区别,未定义和未申明

1
2
3
var a;
typeof a // undefined
typeof b // undefined

根据这个特性,我们举个例子:
在程序中,我们使用DEBUG作为“调试模式”的开关,在输出调试信息到控制台之前,我们会检查DEBUG变量是否已经声明。顶层的全局变量声明 var DEBUG = true 只在debug.js文件中才有,而该文件只有在开发和测试的时候才会被加载到浏览器中,在生产环境不给予加载。我们应该怎么在全局环境中检查DEBUG而不会出现ReferenceError错误,这时候就需要用到typeof

1
2
3
4
5
6
if(DEBUG) { // 这样会抛出异常
console.log('Debugging is starting')
}
if(typeof DEBUG !== 'undefined') {
console.log('Debugging is starting')
}

这不仅对用户定义的变量有用,还对内建的API有用

1
2
3
if(typeof atob === 'undefined') {
atob = function () {}
}
instanceof 操作符的实现原理

instanceof 主要的作用就是判断一个实例是否属于某种类型

1
2
3
4
5
let person = function () {
}
let nicole = new person()
nicole instanceof person // true

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

1
2
3
4
5
6
7
8
9
let person = function () {
}
let programmer = function () {
}
programmer.prototype = new person()
let nicole = new programmer()
nicole instanceof person // true
nicole instanceof programmer // true

根据它的用法,我们可以自己实现一个instanceof方法

1
2
3
4
5
6
7
8
9
10
11
12
13
function new_instance_of (leftValue, rightValue) {
leftValue = leftValue.__proto__;
let rightProto = rightValue.prototype;
while(true) {
if(leftValue === null) {
return false;
}
if(leftValue === rightProto) {
return true;
}
leftValue = leftValue.__proto__;
}
}

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