原文连接javascript
ES5 中有五种基本(原始)数据类型undefined
,null
,boolean
,number
,string
,ES6 中新增了一种基本数据类型:Symbol
。typeof
是咱们开发中最经常使用的判断数据类型的JS原生内置运算符,可是有局限性。java
语法:jquery
typeof运算符后跟操做数:git
typeof ${操做数}
// or
typeof (${操做数})
复制代码
示例:github
typeof(undefined); // undefined
typeof(null); // object
typeof(true); // boolean
typeof(1); // number
typeof(''); // string
typeof(Symbol(1)); // symbol
typeof(function () {}); // function
typeof([]); // object
typeof({}); // object
typeof(new Date()); // object
typeof(/abc/ig); // object
typeof(Math); // object
typeof(new Error('error')); // object
复制代码
这里有两点须要注意的:函数
typeof null
将返回object
。由于在 JS 的最第一版本中,使用的是 32 位系统,为了性能考虑使用低位存储了变量的类型信息,000 开头表明是对象,然而 null 表示为全零,因此将它错误的判断为 object,而后被 ECMAScript 沿用了 。typeof
不能准确判别对象类型到底是什么具体对象。例如typeof {}
,typeof new Date()
, typeof /abc/ig
,typeof Math
,都是返回object
,有没有可能告诉咱们这是一个date
对象,那是一个regexp
对象呢?。还有一个不能忍受的是,typeof []
也是返回object
。不少时候,咱们业务中但愿能准确区分是array
仍是object
。另外,instanceof
也能够判断对象类型,由于内部机制是经过判断对象的原型链中是否是能找到类型的 prototype。可是,并不适用于一些基本数据类型。性能
1 instanceof Number; // false
var num = new Number(1);
num instanceof Number; // true
复制代码
既然typeof
和instanceof
都有局限性,那么有没有一种相对准确的方法来判断数据类型呢?答案是确定的,它就是Object.prototype.toString.call(xxx)
方法,其结果返回格式形如:[object Array]
,[object RegExp]
、[object Date]
等。咱们能够根据其表达式的返回结果中的中括号中的第二个单词,就能准确判别这个数据的具体类型。网上已有不少资料介绍这个函数的用法,它的表现形式也有不少种:测试
1. Object.prototype.toString.call(xxx);
2. ({}).toString.call(xxx);
3. [].toString.call(xxx);
...
复制代码
其实,写法再多也是万变不离其。都是调用了原型链上的原生toString
方法,来为数据类型作强制类型转化。ui
若是咱们只须要准确判断六种基本数据类型,同时又可以准确区分数据类型是function
、array
、仍是object
就足够的话,那么咱们能够这样实现:spa
var superTypeof = function (val) {
var ans = typeof val;
if (ans === 'object') {
if (val === null) {
ans = 'null';
} else if (Array.isArray(val)) {
ans = 'array';
}
}
return ans;
}
复制代码
ps: 若是有兼容性要求的同窗,能够将Array.isArray(val)
语句,改为val instanceof Array
。
测试
superTypeof(undefined); // undefined
superTypeof(null); // null
superTypeof(true); // boolean
superTypeof(1); // number
superTypeof(''); // string
superTypeof(Symbol(1)); // symbol
superTypeof(function () {}); // function
superTypeof([]); // array
superTypeof({}); // object
superTypeof(new Date()); // object
superTypeof(/abc/ig); // object
superTypeof(Math); // object
superTypeof(new Error('error')); // object
...
复制代码
某一天,咱们发现,以上的superTypeof
函数,并不能准确告诉咱们,返回的 Object 类型到底是Date
仍是RegExp
仍是其余比较具体的对象。这个时候,咱们就须要用到上述说起的Object.prototype.toString.call(xxx)
方法了。
var superTypeof = function (val) {
var ans = typeof val;
if (ans === 'object') {
ans = ({}).toString.call(val).slice(8,-1).toLowerCase();
}
return ans;
}
复制代码
测试:
superTypeof(undefined); // undefined
superTypeof(null); // null
superTypeof(true); // boolean
superTypeof(1); // number
superTypeof(''); // string
superTypeof(Symbol(1)); // symbol
superTypeof(function () {}); // function
superTypeof([]); // array
superTypeof({}); // object
superTypeof(new Date()); // date
superTypeof(/abc/ig); // regexp
superTypeof(Math); // math
superTypeof(new Error('error')); // error
...
复制代码
经过这种方式,咱们就能准确判断JS中的数据类型了。
咱们再来看看jquery是怎么实现相似的功能的:
var class2type = {},
typeStr = "Boolean Number String Function Array Date RegExp Object Error Symbol";
typeStr.split(" ").forEach(function (item) {
class2type[ "[object " + item+ "]" ] = item.toLowerCase();
});
var toType = function (obj) {
if ( obj == null ) {
return obj + "";
}
return typeof obj === "object" || typeof obj === "function" ?
class2type[ toString.call( obj ) ] || "object" :
typeof obj;
}
复制代码
是否是以为大同小异的实现方式,甚至还不够我写得优雅呢?其实否则,这有jQuery做者的用意。
最后,我想安利一个有相似功能,且强大精简的库typeof2。