JavaScript 的类型真的是一言难尽,最简单的判断类型的方法是使用 typeof,相信大家都会用,但是得到的类型却比较“宽泛”。
比如 typeof foo ,如果得到的是 'object',那么 foo 可能是object,也可能是 array,还可能是date,也可能是 map,如果要细分的话,还需要再次进行判断。
另外判断类型的方式也不统一,比如上面说的array,用typeof得到的是 object,那么想看看到底是不是数组怎么办呢?到网上搜索会发现各种方法,最后找到了 Array.isArray(foo) 的方法。
这个挺简单的,但是map呢?并没有Map.isMap 的验证方式。
咱们能不能统一一下验证风格呢?
翻了一下vue的源码(shared):
const hasOwnProperty = Object.prototype.hasOwnProperty;
const hasOwn = (val, key) => hasOwnProperty.call(val, key);
const isArray = Array.isArray;
const isMap = (val) => toTypeString(val) === '[object Map]';
const isSet = (val) => toTypeString(val) === '[object Set]';
const isDate = (val) => val instanceof Date;
const isFunction = (val) => typeof val === 'function';
const isString = (val) => typeof val === 'string';
const isSymbol = (val) => typeof val === 'symbol';
const isObject = (val) => val !== null && typeof val === 'object';
const isPromise = (val) => {
return isObject(val) && isFunction(val.then) && isFunction(val.catch);
};
这个是不是有点太奔放了?
获取类型
俗话说的好,自己动手丰衣足食。我们先来做一个获取类型的函数,最全面的方式就是 Object.prototype.toString.call(obj)
,那么我们来用这个获取类型。
只是他返回的是这种形式:'[object Array]'。有点麻烦,我们做个“字典”来翻译一下。
/**
* 做一个字典,映射类型
*/
const dicTypeName = {
'[object Object]': 'object',
'[object Array]': 'array',
'[object Map]': 'map',
'[object Set]': 'set',
'[object Function]': 'function',
'[object AsyncFunction]': 'async',
'[object Promise]': 'promise',
'[object Symbol]': 'symbol',
'[object String]': 'string',
'[object Number]': 'number',
'[object BigInt]': 'bigInt',
'[object RegExp]': 'regExp',
'[object Date]': 'date',
'[object Math]': 'math',
'[object Null]': 'null',
'[object Undefined]': 'undefined'
}
穷举了一下我能想到和找到的类型,如果有遗漏还请大家多多帮忙,先谢过了。
没想到吧,至少十六种。当然 Math 似乎不用判断,因为没有实例。
Promise、async function 也都能区分开,应该是比较全面的了。
只是Proxy的还是区分不出来,返回的是 object。
我们写一些函数来实现功能
/**
* 用 call 的方式获取类型
* @param {*} val 要验证的实例
* @returns
* * '[object Object]',
* * '[object Array]',
* * '[object Map]',
* * '[object Set]',
* * '[object Function]',
* * '[object AsyncFunction]',
* * '[object Promise]',
* * '[object Symbol]',
* * '[object String]',
* * '[object Number]',
* * '[object BigInt]',
* * '[object RegExp]',
* * '[object Date]',
* * '[object Math]',
* * '[object Null]',
* * '[object Undefined]'
*/
const toTypeString = (val) => {
return Object.prototype.toString.call(val)
}
/**
* 获取具体类型
* @param {*} val 要验证的实例
* @returns
* * 'function',
* * 'async',
* * 'object',
* * 'array',
* * 'string',
* * 'number',
* * 'bigInt',
* * 'regExp',
* * 'date',
* * 'map',
* * 'set',
* * 'promise',
* * 'symbol',
* * 'math',
* * 'null',
* * 'undefined'
*/
const typeName = (val) => {
const re = dicTypeName[toTypeString(val)]
if (typeof re === 'string')
return re
else
return 'unknown'
}
验证类型
有时候我们只想知道是不是数组,不需要知道是不是其他的某个类型,这时候可以做一个统一风格的验证方式。
const hasOwnProperty = Object.prototype.hasOwnProperty
const hasOwn = (val, key) => hasOwnProperty.call(val, key)
const isFunction = (val) => typeof val === 'function'
const isAsync = (val) => toTypeString(val) === '[object asyncFunction]'
const isObject = (val) => val !== null && typeof val === 'object'
const isArray = Array.isArray
const isString = (val) => typeof val === 'string'
const isNumber = (val) => toTypeString(val) === '[object Number]'
const isBigInt = (val) => toTypeString(val) === '[object BigInt]'
const isRegExp = (val) => toTypeString(val) === '[object RegExp]'
const isDate = (val) => val instanceof Date
const isMap = (val) => toTypeString(val) === '[object Map]'
const isSet = (val) => toTypeString(val) === '[object Set]'
const isPromise = (val) => toTypeString(val) === '[object Promise]'
const isSymbol = (val) => typeof val === 'symbol'
const isNullOrUndefined = (val) => {
if (val === null) return true
if (typeof val === 'undefined') return true
return false
}
export {
toTypeString, // Object.prototype.toString.call(val)
typeName,
hasOwnProperty,
hasOwn,
isFunction,
isAsync,
isObject,
isArray,
isString,
isNumber,
isBigInt,
isRegExp,
isDate,
isMap,
isSet,
isPromise,
isSymbol,
isNullOrUndefined
}
好吧,还是参考了vue的写法。话说,为啥不直接用vue的代码呢?
网友评论