打个小广告哈,最近做了个小程序,来测测你的工作性价比吧~(微信扫码打开小程序即可)
俗话说,工欲善其事,必先利其器。在我们开始探究vue核心功能之前,先来学习一下vue源码中全局的工具函数,看看vue是如何“利其器”的。
注意,这里的工具函数对应的是src/shared/
下的util.js
,这些函数都是全局通用的,不涉及具体模块(响应式原理啊, 编译啊之类的)。所以介绍的时候仅从函数本身功能的角度出发来解析。阅读本篇文章的之前,你应该有良好的js基础,对于一些概念:原型,闭包,函数柯里化等都有一定的了解。
另一个建议是,你最好先了解一下flow
的基本语法,它是vue2用来做代码静态检查的。由于vue3中即将使用typescript来重写,所以这里也不对flow做过多介绍了。去官网看看基本使用,会对你阅读vue2的源码有帮助。传送门: https://flow.org/
废话不多说,开始吧。
emptyObject
export const emptyObject = Object.freeze({
})
- 作用: 创建一个不可修改的对象
- 拓展: 参考之前的博客,对象的三个安全级别
地址: https://blog.youkuaiyun.com/qq_25324335/article/details/79859407#t2
isUndef
export function isUndef (v: any): boolean %checks {
return v === undefined || v === null
}
- 作用: 检查一个值是不是没有定义,这里检查了它是
undefined
或者null
类型,满足其一就表示它已定义,返回true。
isUndef
export function isDef (v: any): boolean %checks {
return v !== undefined && v !== null
}
- 作用: 检查一个值是不是定义了,必须同时满足它不是
undefined
类型且不是null
类型。
isUndef
export function isTrue (v: any): boolean %checks {
return v === true
}
- 作用: 检查一个值是不是true
isUndef
export function isFalse (v: any): boolean %checks {
return v === false
}
- 作用: 检查一个值是不是false
isPrimitive
// Check if value is primitive
export function isPrimitive (value: any): boolean %checks {
return (
typeof value === 'string' ||
typeof value === 'number' ||
// $flow-disable-line
typeof value === 'symbol' ||
typeof value === 'boolean'
)
}
- 作用: 检查一个值的数据类型是不是简单类型(字符串/数字/symbol/布尔)
- 拓展: js中共有7种数据类型:
Number
,Undefined
,Null
,String
,Boolean
,Object
,Symbol
isObject
/**
Quick object check - this is primarily used to tell
Objects from primitive values when we know the value is a JSON-compliant type.
*/
export function isObject (obj: mixed): boolean %checks {
return obj !== null && typeof obj === 'object'
}
- 作用: 对象的快速检查-这主要是用来将对象从简单值中区分出来
- 拓展: 为什么要检查一下
obj !== null
呢?因为虽然在js中Null
与Object
是两种数据类型,但是使用typeof
操符号的结果是一样的,即typeof null === 'object'
, 所以这里要先排除null
值的干扰
上面几个
isXXX
名称的函数,源码中有这样的一行注释these helpers produces better vm code in JS engines due to their explicitness and function inlining
,主要是说这几个函数是用来各司其职的检查数据类型的。我们也可以借鉴这种写法,写业务逻辑的时候,应该拆分成最小的单元,这样各单元功能明确,代码可读性也更高。
toRawType
const _toString = Object.prototype.toString
// Get the raw type string of a value e.g. [object Object]
export function toRawType (value: any): string {
return _toString.call(value).slice(8, -1)
}
-
作用: 获取一个值的原始类型字符串
-
拓展: 在任何值上调用Object原生的toString方法,都会返回一个
[object NativeConstructorName]
格式的字符串。每个类在内部都有一个[[Class]]
的内部属性,这个属性就指定了这个NativeConstructorName
的名称。例如Object.prototype.toString.call([]) // "[object Array]" Object.prototype.toString.call(1) // "[object Number]" ...
所以上述 toRawType 函数实际上是把
[object Number]
这个字符串做了截取,返回的是类型值,如"Number", "Boolean", "Array"
等
isPlainObject
// Strict object type check. Only returns true for plain JavaScript objects.
export function isPlainObject (obj: any): boolean {
return _toString.call(obj) === '[object Object]'
}
-
作用: 严格的类型检查,只在是简单js对象返回true
-
拓展: 为什么特意加一句
Only returns true for plain JavaScript objects.
呢?因为有一些值,虽然也属于js中的对象,但是有着更精确的数据类型,比如:Object.prototype.toString.call([]) // "[object Array]" Object.prototype.toString.call(()=>{ }) // "[object Function]" Object.prototype.toString.call(