数据类型检测有四种办法:
- typeof
- instanceof & constructor
- Object.prototype.toString.call(value)
- 封装一个数据类型检测的方法库。
typeof
用来检测数据类型的运算符
「语法」: typeof [value]
「返回值」: 返回值是个字符串。例如 'unfefined'、'number'、'object'、'boolean'、'symbol'......
【局限】
null 是基本数据类型,但是typeof null => 'object'
不能具体区分对象数据类型的值。
typeof [] ==> 'object'
typeof {} ==>'object'
typeof /^$/ ==>'object'
【优势】 速度快。使用方便。所以在真实项目中,我们也会大量应用它来进行检测。尤其是在检测基本数据类型值(null除外)和函数类型值的时候,还是比较方便的。
例子:
// 检测形参的值是否为空
function query(n,m,callback){
//方式1
ES6默认值: function query(n=0,m=0){}
//方式2 检测形参的值是否为undefined
n === undefined ? n=0:null;
typeof m === 'undefined' ? m = 0:null;
//方式3 基于逻辑运算符 但这种方式不够严谨,如果n或者m传递的是false 也会导致前面条件为假
n = n || 0;
m = m || 0;
// 判断是否有回调函数
typeof callback === 'function' ? callback() : null;
// 使用短路运算符 callback && callback() 如果callback 位置用户传了true,但是callback并不是函数,也会执行。所以不够严谨。
}
instanceof
本意是用来检测某个实例是否隶属于某个类的运算符。 可以用来做某些数据类型的检测;
let arr = [],
reg = /^$/;
console.log(arr instanceof Array) // true
console.log(reg instanceof Array) // false
【局限】
不能处理基本数据类型。 只要在当前实例的原型链中出现过的类,检测结果都是true
console.log(1 instanceof Number) // false
console.log(arr instanceof Object) // true
constructor
构造函数
原理: 在类的原型上一般都会带一个constructor 属性,存储的是当前类本身。我们也是利用这一点,验证是否为所属的类。
【局限】 太容易被修改了。
let n = 12,
arr = [];
console.log(n.constructor === Number) // true
console.log(arr.constructor === Array) // true
console.log(arr.constructor === Object) // false
// 如果我们给arr 添加一个私有属性 constructor
arr.constructor = 'God';
console.log(arr.constructor === Array) // false
Object.prototype.toString.call(value)
调用Object原型上的toString 方法,让方法执行的时候方法中的this变成要检测的数据类型,从而获取到数据类型所属类的详细信息。该信息有个标准模板: "[object 所属类]"
function func(){
};
let obj1 = {},
obj2 = {
name:'hhh'
};
console.log([1,2].toString()) // '1,2'
console.log(/^$/.toString()) // "/^$/"
console.log(func.toString()) // "function(){}"
console.log(obj1.toString()) // "[object Object]"
console.log(obj2.toString()) // "[object Object]"
在所有的数据类型类中,他们的原型上都有toString方法。除了Object.prototype.toString不是把数据值转为字符串,其余都是。而Object原型上的toString是检测当前实例隶属类的详细信息的(检测数据类型)。
这个方法很强大,所有数据类型隶属的类信息检测的一清二楚。
封装类型检测方法
// 第一种
let _type = function(obj){
const toString = Object.prototype.toString;
const typeMap = {
'[object String]' :'string',
'[object Number]':'number',
'[object Boolean]' :'boolean',
'[object Array]' :'array',
'[object Function]' :'function',
'[object Null]' :'null',
'[object Undefined]' :'undefined',
'[object Object]' :'object',
'[object Date]' :'date',
'[object RegExp]' :'regExp'
};
return typeMap[toString.call(obj)];
};
console.log(_type(1) === 'number')
console.log(_type(Array) === 'function') // true js中任何类都是函数。Array是类,属于函数。它的实例对象是个数组
第二种:
// let typeMap = {
// 'isString':'[object String]',
// 'isNumber':'[object Number]',
// 'isBoolean':'[object Boolean]',
// 'isArray':'[object Array]',
// 'isFunction':'[object Function]'
// };
// let __type = {};
// let toString = Object.prototype.toString;
// for(var key in typeMap){ // 由于这里用的是var 所以为了防止最后调用的时取出的key是最后一次赋的值。用闭包来解决,也可以直接将这里改成let ,就可以不用写闭包
// if(!typeMap.hasOwnProperty(key)) break;
// __type[key] = (function(){
// var value = typeMap[key];
// return function(obj){
// return toString.call(obj) === value;
// }
// })()
// }
let typeMap = {
'isString': 'String',
'isNumber':'Number',
'isBoolean':'Boolean',
'isArray':'Array',
'isFunction':'Function',
'isDate':'Date',
'isObject':'Object',
'isRegExp':'RegExp',
'isNull':'Null',
'isUndefined':'Undefined'
};
let _toString = Object.prototype.toString;
let __type = {};
for(let key in typeMap){
__type[key] = function(obj){
let reg = new RegExp('\\[object '+typeMap[key]+'\\]');
return reg.test(_toString.call(obj))
}
}
__type.isString('')