JavaScript如何优雅地得到正确的数据类型

120 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

1、instanceof

格式:value instanceof Object
使用这个关键字可以判断数据是否属于某个类型,返回true或false
例如:

let a = 10;
let a2=new Number(10);
let obj = {
    name: 'zf',
    age: 38
}
let b = null;
let d = undefined;
let namearr = ['asd', 'qew', 'asrt', 'kanzo'];
console.log('========instanceof=============')
console.log(a instanceof Number)  //false
console.log(a2 instanceof Number)  //true
console.log(Object instanceof Object)   //true
console.log(b instanceof Object)   //false
console.log(b instanceof Null)   //Uncaught ReferenceError: Null is not defined
console.log(d instanceof undefined)  //Uncaught TypeError: Right-hand side of 'instanceof' is not an object
console.log(namearr instanceof Object)  //true
console.log(namearr instanceof Array)  //true

用这个方法检测数据类型是不可靠的
①无法检测出值为null、undefined的变量。
②在检测引用数据类型时也会产生歧义。诚然Array是派生自Object,它既是对象也是数组,但为了消除歧义使得在判断时,需要做更多的工作。(如function、regExp、argument等类型)
③只能检测出显式装箱的基本数据类型。

此外,要使用instanceof判断一个类型未知的数据,需遍历很多数据类型尝试是否有一个为true,这显然也不是一个聪明的办法。

2、typeof

格式: typeof value
使用这个关键字可以返回数据的数据类型

let a = 10;
let a2 = new Number(10);
let obj = {
    name: 'zf',
    age: 38
}
let b = null;
let d = undefined;
let namearr = ['asd', 'qew', 'asrt', 'kanzo'];
console.log('========typeof================')
console.log(typeof a)  //number
console.log(typeof a2)  //object
console.log(typeof obj)  //object
console.log(typeof b)  //object
console.log(typeof d)  //undefined
console.log(typeof namearr)  //object

emmm,已经有很大进步了,至少typeof直接把可能正确的数据类型返回给了我们,这比用instanceof一个一个试更加容易,但它依旧不可靠
①检测null类型,错误的返回了object。这是JavaScript创立时遗留的历史问题,有更好的方法解决它。
②将基本类型对应的显式装箱,返回成了对象。与Array相同,虽然没错,但不是我们想要的。

3、Object.prototype.toString.call(TargetObject)

首先要将Object.prototype.toString方法与其他类型的toString方法区分开来。
toString最初是Object原型的方法,但Array、Function、Arguments等对象作为Object的实例,都对toString函数进行了重写。
以数组为例子,Object.prototype.toString和Array.toString是两个不同的函数。
Object.prototype.toString方法可以得到对象的具体类型
Array.toString方法则是将数组转换成字符串

let a = 10;
let a2 = new Number(10);
let obj = {
    name: 'zf',
    age: 38
}
let b = null;
let d = undefined;
let namearr = ['asd', 'qew', 'asrt', 'kanzo'];
console.log('========Object.prototype.toString=============')
console.log(Object.prototype.toString.call(a))  //[object Number]
console.log(Object.prototype.toString.call(a2))  //[object Number]
console.log(Object.prototype.toString.call(obj))  //[object Object]
console.log(Object.prototype.toString.call(b))  //[object Null]
console.log(Object.prototype.toString.call(d))  //[object Undefined]
console.log(Object.prototype.toString.call(namearr))  //[object Array]
console.log(namearr.toString())  //asd,qew,asrt,kanzo

Object.prototype.toString.call(target)会以字符串的形式返回target的数据类型。
Object.prototype.toString方法几乎是一个完美的解决方案了,装箱和未装箱的基本类型、null、undefined数据类型都能正确给出。
题外话:Object.prototype身上还有很多好用的函数,用call借调Object.prototype身上函数的情况是会经常遇到的。

4、封装函数myTypeof()

如果对[object Number]的输出格式不太满意,我们可以对Object.prototype.toString方法进行函数封装,根据自己的需求加入一些功能,比如得到一个更满意的数据类型输出格式。

let a = 10;
let myTypeof = function (target) {
    let type = Object.prototype.toString.call(target).match(/\[object (\w+)\]/);
    return type ? type[1] : '';
}
console.log(myTypeof(a))  //Number