一次性讲清楚js中的数据类型检测
(1)四种常见方案
- typeof
- instanceof
- constructor
- Object.prototype.toString.call(value)
(2)typeof
- 原理
typeof是在计算机底层根据js数据类型的二进制的值进行检测的。在JavaScript中,用32个二进制位来标识JavaScript中的值,其中低三位来表示值的类型。000表示对象,010表示浮点数,100表示字符串,110表示布尔值,001表示整数,-2^30表示undefined,全0表示null。 - 类型判断结果
value typeof value 数值/NaN/Infinity ‘number’ 字符串 ‘string’ true/false ‘boolean’ undefined ‘undefined’ null ‘object’ 大整数 ‘bigint’ Symbol类型 ‘symbol’ 函数 ‘function’ 非函数对象 ‘object’ - 总结
从上面表格可以发现typeof能较好地判断基本数据类型(null除外);而对于引用数据类型,则只能判断function类型的数据。 - 问题1:typeof null 检测出来的结果为什么是object?
typeof是根据二进制值来判断数据类型的,null 的二进制值是全0,而 object 类型的二进制值都是 000 开头的,所以typeof检测null时也被检测成object。(可以理解为这是JavaScript历史遗留下来的bug) - 问题2:为什么typeof判断函数可以判断出是function类型(而不是object)?
虽然在JavaScript中函数也是对象,但是在进行typeof判断时候,如果遇到函数时会自动调用call方法来判断。
(3)instanceof
-
原理
只要当前类在被检测的实例的原型链上,结果都是true。console.log([] instanceof Array)//true console.log([] instanceof RegExp)//false console.log([] instanceof Object)//也是true
最后一行可能有人觉得奇怪,后续我会花专门章节分析原型链相关知识。在这大致解释起来就是空数组[]这个被检测的实例的原型链上有Array、Object。
-
一些弊端
可以肆意修改原型的指向,会导致检测出来的值可能不准确function Fn(){ this.x=10; } Fn.prototype=Object.create(Array.prototype); let f=new Fn(); console.log(f instance Array)//true
并且instanceof不能检测基本数据类型。
-
手写instanceof
function myInstance(example,classFunc){ // 实例.__proto__===类.prototype if(typeof example !=="object" || example ===null){ return false; } //获取参数的原型对象 let proto=Object.getPrototypeOf(example); //这里没有用 example.__proto__,因为IE浏览器不兼容 while(true){ if(proto===null){ return false; } if(proto===classFunc.prototype){ return true; } proto=Object.getPrototypeOf(proto) } }
(4)constructor
- 用起来比instanceof似乎好一些(也支持基本数据类型)
let arr=[]; console.log(arr.constructor===Array);//true console.log(arr.constructor===RegExp);//false console.log(arr.constructor===Object);//false let n=1; console.log(n.constructor===Number);//true
- constructor可以随意改变,所以也不准确
Number.prototype.constructor="AA"; let n=1; console.log(n.constructor===Number);//false
(5)Object.prototype.toString.call(value)
- Object.prototype.toString不是转换为字符串,是返回当前实体所属类的信息,call是改变this指向
- 可以检测所有类型的值
[object Number] [object String] [object Boolean] [object Null] [object Undefined] [object Symbol] [object Object] [object Array] ...等等
(6)封装一个检测数据类型的方法
- 思路
基本数据类型用typeof判断,引用数据类型用Object.prototype.toString.call判断 - 代码
function getType(obj){ //简约undefined和null if (obj==null){ return obj+""; } if (typeof obj =='object' || typeof obj =='function'){ let typeStr = Object.prototype.toString.call(obj) // 解析[object String] typeStr = typeStr.split(' ')[1] type = typeStr.substring(0, typeStr.length - 1) return type.toLowerCase(); } return typeof obj; }