前言
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') === 'symbol
typeof 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 === true
new RegExp() instanceof RegExp === true
看上去还真可以判断引用类型的数据,其实不会很准确,这不是它设计的初衷。例如:
[] instanceof Array === true
[] instanceof Object === true
const a =function(){}; a instanceof Object === true
所以 Vue 中很少用 instanceof 运算符去判断数据的类型,只用来判断实例化对象是不是某个类实例化出来的。例如:
if ( !(this instanceof Vue) ){}
if( vnode instanceof VNode ){}