前言
Vue 框架作为一个成熟的框架,里面有很多值得去学习、借鉴、使用。本专栏主要学习 Vue 中如何判断数据类型。
一、数据类型
到 ECMAScript 10 为止,规定了 8 种 数据类型,又把数据类型分为原始类型和对象类型。
原始类型
| 名称 | 描述 |
|---|---|
| Null | 只包含一个值:null。 |
| Undefined | 只包含一个值:undefined。 |
| Boolean | 布尔值包含两个值:true和false。 |
| Number | 数值,例如整数或浮点数,还有一些特殊值(-Infinity、+Infinity、NaN)。 |
| String | 字符串。 |
| Symbol | 一种实例是唯一且不可改变的数据类型,ES6引入。 |
| BigInt | 用于当整数值大于Number数据类型支持的范围时,ES10引入。 |
引用类型
| 名称 | 描述 |
|---|---|
| Object | Object 对象、Array 数组、Function 函数、Date 日期、RegExp 正则 等等 |
二、Vue中如何判断原始类型
function isPrimitive(value) {
return (
typeof value === 'string' ||
typeof value === 'number' ||
typeof value === 'symbol' ||
typeof value === 'boolean'
)
}
原因
typeof operand,参数 operand 一个表示对象或原始值的表达式,其类型将被返回。
typeof undefined === 'undefined'typeof true === 'boolean'typeof 3.14 === 'number'typeof 'bla' === 'string'typeof Symbol('foo') === 'symboltypeof 42n === 'bigint'typeof null === 'object'
从以上可以总结,原始类型的数据除了 null 其它都可以用 typeof 准确判断出来。
三、Vue中如何判断引用类型
function isObject(obj) {
return obj !== null && typeof obj === 'object'
}
其实 Vue 漏掉了对 Function 函数的判断,完整的判断,如下所示:
function isObject(obj) {
return obj !== null && ( typeof obj === 'object' || typeof obj === 'function' )
}
原因
typeof operand,参数 operand 一个表示对象或原始值的表达式,其类型将被返回。
typeof function() {} === 'function'typeof null === 'object'typeof {a: 1} === 'object'typeof [1, 2, 4] === 'object'typeof new Date() === 'object'typeof /regex/ === 'object'typeof new Boolean(true) === 'object'typeof new Number(1) === 'object'
从以上可以总结,原始类型的数据除了 null 其它都可以用 typeof 准确判断出来。引用类型的数据就无法用 typeof 准确判断出来,返回的值都是 object。
四、Vue中如何判断对象
const _toString = Object.prototype.toString;
function isPlainObject(obj){
return _toString.call(obj) === '[object Object]'
}
原因
toString 方法是 Object 的一个实例方法,Object.prototype.toString。在JavaScript中,几乎所有的对象都是 Object 类型的实例,它们都会从 Object.prototype 继承属性和方法。而 Object 是个引用类型。所以每个引用类型都有 toString 方法,都从 Object.prototype 继承属性和方法,而且在引用类型上若这个方法未被自定义,那么使用 toString 方法,其返回 [object type],其中 type 是对象的类型,这样就可以用 toString 方法来判断引用类型的数据的类型。
因为引用类型上的 toString 方法,可能会被自定义。比如Array、Date、RegExp等都自定义了toString 方法。
故要调用 Object.prototype.toString,并使用 call来将 this 指向要判断的数据,例如:
Object.prototype.toString.call([]) === "[object Array]"Object.prototype.toString.call({}) === "[object Object]"Object.prototype.toString.call(function (){}) === "[object Function]"Object.prototype.toString.call(/df/) === "[object RegExp]"Object.prototype.toString.call(new Date()) === "[object Date]"
五、Vue中如何判断正则表达式
const _toString = Object.prototype.toString
function isRegExp(v){
return _toString.call(v) === '[object RegExp]'
}
原因
如第四点的原因所示。
六、补充
toString
从上面得知使用 Object.prototype.toString 可以准确地判断出引用类型的数据的类型。那对于原始类型的数据呢?
会发现以下等式也成立:
Object.prototype.toString.call(true) === "[object Boolean]"Object.prototype.toString.call(123) === "[object Number]"Object.prototype.toString.call('123') === "[object String]"
这是为什么呢?不是说 toString 是引用类型的数据的方法。
这是 call 方法在起作用。我们来看一下在 MDN上对 call 方法的用法介绍。
function.call(thisArg, arg1, arg2, ...)
- 参数
thisArg:可选的。在function函数运行时使用的this值。请注意,this可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为null或undefined时会自动替换为指向全局对象,原始值会被包装。 - 参数
arg1, arg2, ...:指定的参数列表。
按上述所介绍,在非严格模式下,若 thisArg 是原始值会被包装。那什么是包装。现有的JS中有三个包装器 new Number() 、
new String() 、new Boolean()。
例如,参数 thisArg 为 123 时,在 call 方法内部会执行 new Number(123) 把 123 包装一下,而 new Number(123) 是个引用类型,可以调用 toString 方法。故使用 Object.prototype.toString 来判断 Number 、String、Boolean 这三个原始类型的数据类型。
对于 Symbol 类型的原始数据,其是用 Symbol() 函数创建的,返回的值上面也有 toString 方法,故Object.prototype.toString.call(Symbol()) === "[object Symbol]"。
对于 BigInt 类型的原始数据,其 BigInt 是一种内置对象,属性上面也有 toString 方法,故Object.prototype.toString.call(42n) === "[object BigInt]"。
至于对 null 、 undefined 类型的原始数据,可能是在 Object.prototype.toString 源码中做了处理,也可以判断出来。
Object.prototype.toString.call(null) === "[object Null]"Object.prototype.toString.call(undefined) === "[object Undefined]"
可以看出使用Object.prototype.toString能最全面的判断数据类型。
instanceof
object instanceof constructor:instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。
object某个实例对象constructor某个构造函数
从 instanceof 运算符的定义来看,可以弥补 typeof 无法判断引用类型的数据。例如:
new Date() instanceof Date === truenew RegExp() instanceof RegExp === true
看上去还真可以判断引用类型的数据,其实不会很准确,这不是它设计的初衷。例如:
[] instanceof Array === true[] instanceof Object === trueconst a =function(){}; a instanceof Object === true
所以 Vue 中很少用 instanceof 运算符去判断数据的类型,只用来判断实例化对象是不是某个类实例化出来的。例如:
if ( !(this instanceof Vue) ){}
if( vnode instanceof VNode ){}