Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JS怎么准确判断数据类型? #10

Open
Checkson opened this issue Feb 14, 2019 · 0 comments
Open

JS怎么准确判断数据类型? #10

Checkson opened this issue Feb 14, 2019 · 0 comments

Comments

@Checkson
Copy link
Owner

Checkson commented Feb 14, 2019

前言

ES5 中有五种基本(原始)数据类型undefinednullbooleannumberstring,ES6 中新增了一种基本数据类型:Symboltypeof是我们开发中最常用的判断数据类型的JS原生内置运算符,但是有局限性。

typeof 运算符

语法:

typeof运算符后跟操作数:

typeof ${操作数}
// or
typeof (${操作数})

示例:

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/igtypeof Math,都是返回object,有没有可能告诉我们这是一个date对象,那是一个regexp对象呢?。还有一个不能忍受的是,typeof []也是返回object。很多时候,我们业务中希望能准确区分是array还是object

另外,instanceof 也可以判断对象类型,因为内部机制是通过判断对象的原型链中是不是能找到类型的 prototype。但是,并不适用于一些基本数据类型。

1 instanceof Number; // false
var num = new Number(1);
num instanceof Number; // true

思考

既然typeofinstanceof都有局限性,那么有没有一种相对准确的方法来判断数据类型呢?答案是肯定的,它就是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方法,来为数据类型做强制类型转化。

实践

场景一

如果我们只需要准确判断六种基本数据类型,同时又能够准确区分数据类型是functionarray、还是object就足够的话,那么我们可以这样实现:

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 实现方式

我们再来看看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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant