typeof
除了null,所有的原始类型都可以使用typeof运算符进行测试。
- 从概念上讲,undefined表示值的缺失,null表示对象的缺失(这也可以说明typeof null === 'object'的原因)。
- NaN(“Not a Number”)
判断数据类型的缺陷
typeof null、typeof []、typeof /a/...这些返回的都是Object。
instanceof
语法
object instanceof constructor
- object 某个实例对象
- constructor 某个构造函数
描述
instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上。
手写instanceof
function myInstanceof(obj, constructor) {
if (obj === null) return false
let prototype = Object.getPrototypeOf(obj)
if (prototype === constructor.prototype) {
return true
} else {
return myInstanceof(prototype, constructor)
}
}
判断数据类型的缺陷
- 对于字面量声明的基础类型无法识别
1 instanceof Number // false
new Number(1) instanceof Number // true
- 对于
[] instanceof Object这类也会返回true, 所以可能无法准确的判断Array、Date、RegExp等
[] instanceof Array // true
[] instanceof Object // true
Object.prototype.toString()
Object.prototype.toString()是比较完善的判断数据类型的方案。
Object.prototype.toString.call(null) // '[object Null]'
Object.prototype.toString.call(undefined) // '[object Undefined]'
Object.prototype.toString.call(true) // '[object Boolean]'
Object.prototype.toString.call(1) // '[object Number]'
Object.prototype.toString.call('a') // '[object String]'
Object.prototype.toString.call(new Symbol()) //'[object Symbol]'
Object.prototype.toString.call({}) // '[object Object]'
Object.prototype.toString.call([]) // '[object Array]'
Object.prototype.toString.call(new Date()) // '[object Date]'
Object.prototype.toString.call(/a/) // '[object RegExp]'
value.constructor.name;
({}).constructor.name // 'Object'
[].constructor.name // 'Array'
new Date().constructor.name // 'Date'
/a/.constructor.name 'RegExp'
value.constructor.name判断数据类型的缺陷
无法判断字面量声明的基础类型。
Array.isArray()
只是判断是否数组。
MDN官方提供的检查数据类型的方法
function type(value) {
if (value === null) {
return "null";
}
const baseType = typeof value;
// 基本类型
if (!["object", "function"].includes(baseType)) {
return baseType;
}
// Symbol.toStringTag 通常指定对象类的“display name”
// 它在 Object.prototype.toString() 中使用。
const tag = value[Symbol.toStringTag];
if (typeof tag === "string") {
return tag;
}
// 如果它是一个函数,其源代码以 "class" 关键字开头
if (
baseType === "function" &&
Function.prototype.toString.call(value).startsWith("class")
) {
return "class";
}
// 构造函数的名称;例如 `Array`、`GeneratorFunction`、`Number`、`String`、`Boolean` 或 `MyCustomClass`
const className = value.constructor.name;
if (typeof className === "string" && className !== "") {
return className;
}
// 在这一点上,没有合适的方法来获取值的类型,因此我们使用基本实现。
return baseType;
}
Symbol.toStringTag
对象可以通过定义Symbol.toStringTag属性来更改Object.prototype.toString()的行为
function MyDate() {
}
Object.prototype.toString.call(MyDate) // '[object Function]'
MyDate[Symbol.toStringTag] = 'MyDate'
Object.prototype.toString.call(MyDate) // '[object MyDate]'
Vue中判断数据类型的源码
export const isArray = Array.isArray
export const isMap = (val: unknown): val is Map<any, any> =>
toTypeString(val) === '[object Map]'
export const isSet = (val: unknown): val is Set<any> =>
toTypeString(val) === '[object Set]'
export const isDate = (val: unknown): val is Date =>
toTypeString(val) === '[object Date]'
export const isRegExp = (val: unknown): val is RegExp =>
toTypeString(val) === '[object RegExp]'
export const isFunction = (val: unknown): val is Function =>
typeof val === 'function'
export const isString = (val: unknown): val is string => typeof val === 'string'
export const isSymbol = (val: unknown): val is symbol => typeof val === 'symbol'
export const isObject = (val: unknown): val is Record<any, any> =>
val !== null && typeof val === 'object'
export const isPromise = <T = any>(val: unknown): val is Promise<T> => {
return (
(isObject(val) || isFunction(val)) &&
isFunction((val as any).then) &&
isFunction((val as any).catch)
)
}
export const objectToString = Object.prototype.toString
export const toTypeString = (value: unknown): string =>
objectToString.call(value)
11