typeof
实现原理
一个 js
的变量,在它的底层实现中,它的类型信息是怎么实现的呢
其实,js
在底层存储变量的时候,会在变量的机器码的低位1-3
位存储其类型信息
- 000:对象
- 010:浮点数
- 100:字符串
- 110:布尔
- 1:整数
但是,对于 undefined
和 null
来说,这两个值的信息存储是有点特殊的。
null
:所有机器码均为0
undefined
:用 −2^30 整数来表示
所以,typeof
在判断 null
的时候就出现问题了,由于 null
的所有机器码均为0,因此直接被当做了对象来看待。
然而用 instanceof
来判断的话
null instanceof null // TypeError: Right-hand side of 'instanceof' is not an object
null
直接被判断为不是 object
,这也是 JavaScript
的历史遗留bug
。
因此在用 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 // true
nicole instanceof programmer // true
这是 instanceof
的用法,但是 instanceof
的原理是什么呢?
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
,告诉我们左边变量并非是右边变量的实例。
instanceof
建议版本实现原理
while (x.__proto__) {
if (x.__proto__ === y.prototype) {
return true;
}
x.__proto__ = x.__proto__.__proto__;
}
if (x.__proto__ === null) {
return false;
}
Q.E.D.