✍Vue源码——学习如何判断数据类型

时间:2021-1-18 作者:admin

前言

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 function() {} === 'function'
  • typeof null === 'object'

从以上可以总结,原始类型的数据除了 null 其它都可以用 typeof 准确判断出来。

三、Vue中如何判断引用类型

function isObject(obj) {
    return obj !== null && typeof obj === 'object'
}

原因

typeof operand,参数 operand 一个表示对象或原始值的表达式,其类型将被返回。

  • 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可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为 nullundefined 时会自动替换为指向全局对象,原始值会被包装。
  • 参数 arg1, arg2, ... :指定的参数列表。

按上述所介绍,在非严格模式下,若 thisArg 是原始值会被包装。那什么是包装。现有的JS中有三个包装器 new Number()
new String()new Boolean()

例如,参数 thisArg123 时,在 call 方法内部会执行 new Number(123)123 包装一下,而 new Number(123) 是个引用类型,可以调用 toString 方法。故使用 Object.prototype.toString 来判断 NumberStringBoolean 这三个原始类型的数据类型。

对于 Symbol 类型的原始数据,其是用 Symbol() 函数创建的,返回的值上面也有 toString 方法,故Object.prototype.toString.call(Symbol()) === "[object Symbol]"

对于 BigInt 类型的原始数据,其 BigInt 是一种内置对象,属性上面也有 toString 方法,故Object.prototype.toString.call(42n) === "[object BigInt]"

至于对 nullundefined 类型的原始数据,可能是在 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 ){}
声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。