JS 数据类型判定 typeof原理 instanceof原理
typeof
typeof 一般被用于判断一个变量的类型,我们可以利用 typeof 来判断number, string, object, boolean, function, undefined, symbol 这七种类型,这种判断能帮助我们搞定一些问题;但是,很遗憾的一点是,typeof 在判断一个 object的数据的时候只能告诉我们这个数据是 object, 而不能细致的具体到是哪一种 object。
原理
其实,js 在底层存储变量的时候,会在变量的机器码的低位1-3位存储其类型信息👉
-
000:对象 010:浮点数 100:字符串 110:布尔 1:整数
but, 对于 undefined 和 null 来说,这两个值的信息存储是有点特殊的。
null:所有机器码均为0
undefined:用 −2^30 整数来表示
所以,typeof 在判断 null 的时候就出现问题了,由于 null 的所有机器码均为0,因此直接被当做了对象来看待。
因此在用 typeof 来判断变量类型的时候,我们需要注意,最好是用 typeof 来判断基本数据类型(包括symbol),避免对 null 的判断。
缺陷
-
无法区分 object 和 null,typeof null 的值为 object
typeof null // object
-
无法判断具体为哪一种对象类型
typeof new Array() // object typeof new String(123) // object typeof new Number(1) // object
instanceof
instanceof 主要的作用就是判断一个实例是否属于某种类型,也可以判断一个实例是否是其父类型或者祖先类型的实例。
原理
其实 instanceof 主要的实现原理就是只要右边变量的 prototype 在左边变量的原型链上即可。因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果查找失败,则会返回 false,告诉我们左边变量并非是右边变量的实例。
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__ } }
缺陷
-
无法判断 null、undefined 无法判断字面量形式数据的数据类型
1 instanceof Number // false missy instanceof String // false
Object.prototype.toString.call
我们可以利用这个方法来对一个变量的类型来进行比较准确的判断
Object.prototype.toString.call({ }) // [object Object] Object.prototype.toString.call([]) // [object Array] Object.prototype.toString.call(() => { }) // [object Function] Object.prototype.toString.call(seymoe) // [object String] Object.prototype.toString.call(1) // [object Number] Object.prototype.toString.call(true) // [object Boolean] Object.prototype.toString.call(Symbol()) // [object Symbol] Object.prototype.toString.call(null) // [object Null] Object.prototype.toString.call(undefined) // [object Undefined] Object.prototype.toString.call(new Date()) // [object Date] Object.prototype.toString.call(Math) // [object Math] Object.prototype.toString.call(new Set()) // [object Set] Object.prototype.toString.call(new WeakSet()) // [object WeakSet] Object.prototype.toString.call(new Map()) // [object Map] Object.prototype.toString.call(new WeakMap()) // [object WeakMap]```
总结
简单来说,我们使用 typeof 来判断基本数据类型是 ok 的,不过需要注意当用 typeof 来判断 null 类型时的问题,如果想要判断一个对象的具体类型可以考虑用 instanceof,但是 instanceof 也可能判断不准确,比如一个数组,他可以被 instanceof 判断为 Object。所以我们要想比较准确的判断对象实例的类型时,可以采取 Object.prototype.toString.call 方法。