封装JS数据类型检测

691 阅读2分钟

数据类型检测有四种办法:

  1. typeof
  2. instanceof & constructor
  3. Object.prototype.toString.call(value)
  4. 封装一个数据类型检测的方法库。

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('')