开始读源码之——Vue2工具函数

215 阅读5分钟

从易到难读源码。

今天读的源码是 Vue2 中的 util.js 工具函数库。

直接阅读 Vue2 源码会比较吃力,但其中的 util.js 工具函数库还是比较简单易懂。

虽然代码使用了 flow 来标注类型,但忽略掉类型标注的部分,不影响阅读。

1. emptyObject

赋值一个冻结后的对象。该变量可用于一些兼容写法的场景,例如:const a = b.c || emptyObject; 由于对象是被冻结的,所以可以用作判断 if (a === emptyObject) 的情况。

2. isUndef、isDef

判断一个变量是否有定义,只要不是undefined和null就认为被定义了。

3. isTrue、isFalse

功能如名。

4. isPrimitive

判断一个变量是否是原始值,即是否为 String、Number、Boolean、Symbol 类型的一种。

5. isObject

判断一个变量是否为非null的对象。这是为了解决js语言中 typeof null === 'object' 的问题。

6. toRawType

返回一个变量的真实类型,基本上是我们期望的类型。内部使用了 Object.prototype.toString().call() 的方法。

7. isPlainObject

返回一个变量是否为纯对象,排除了数组和null的情况。也使用了Object.prototype.toString().call() 的方法。

8. isRegExp

是否为正则表达式。也使用了Object.prototype.toString().call() 的方法。

9. isValidArrayIndex

判断一个值是否可用于数组的下标值。number类型或纯数字字符串,大于等于0,整数,有限(非NaN和非无穷大无穷小)。

这里学到了一个 isFinite() 全局方法,对该方法传入 NaN、正负无穷大 时,会返回false,否则传入其它数字类型或纯数字字符串的值,会返回true。

10. isPromise

判断是否是 promise 。假如一个值是被定义的(不为null和undefined),并且它的 .then() 和 .catch() 方法都存在,就认为是一个 promise 。

11. toString

转为字符串;

如果是null则返回空字符串;

如果是数组或对象并且对象的toString方法未被修改,则使用 JOSN.stringify 转换;

否则使用 String() 转换。

12. toNumber

转为数字;

若转换失败则返回原值。

13. makeMap

创建一个map,并返回一个方法检查map中是否存在传入的key值;

使用这个方法,会期望传入一个包含逗号的字符串,将字符串用逗号分割后的所有字符串作为key存入创建的map中,并返回检查某一个key是否存在的方法。

这个方法可能会用在什么场景呢?需要到vue源码中去找答案了。。。

14. isBuiltInTag

这里马上用到 makeMap 了。检查一个字符串是否为 内置tag,目前 tag,component,Tag,Component 是内置tag。

15. isReservedAttribute

是否保留属性。

key,ref,slot,slot-scope,is 这些是保留属性

16. remove

从数组中移除某一项。

对于用splice移除个人觉得没有问题。因为我对此 remove 方法的使用场景未知。如果是个通用场景,那么调用者自然会希望 remove 后返回的数组,是一个普通的可以正常遍历的数组。当然如果使用位置都是针对固定场景,如axios中的拦截器场景,那么移除时设为null,后续调用时判断null才比较好。

17. haOwn

判断是否为对象自己的属性,不能是原型链上的属性和方法。

18. cached

每当调用此方法,都会创建一个新的闭包cache对象来进行缓存,此方法的返回值,是具体的缓存方法,调用返回值方法可取出cache中的缓存数据或存入数据。

其中有个平时没注意到的点:

function () { //... ; return hit || (cache[str] = fn(str)) }

这样的写法,会将 cache[str] 先赋值后,再将 cache[str] 的值返回。

19. camelize

将短线连接的字符串如 on-click 转为小驼峰写法 onClick 。这里用到了 cached 的方法,即相同的字符串不重复转换,直接返回缓存的内容。这里也可以看出 cached 只支持新增不支持修改的原因,因为没有修改的需求。

20. capitalize

首字母转大写。

同19.

21. hyphenate

小驼峰转连字符。跟19相反。

22. polyfillBind

bind 方法的 polyfill ,使用 apply 和 call 实现。

23. toArray

将类数组转为真数组的方法。可以看到使用了 while 遍历给新数组复制的办法,可以想到,是因为 vue2 需要兼容老版本的浏览器,所以没有使用诸如 [...list] 的结构方法来实现。

24. extend

合并两个对象。也是使用了循环赋值的方法,将 _from 中的属性都遍历赋值给 to 对象。

同23,如果不考虑兼容性可以直接 { ...to, ...from} 。

25. toObject

将一个元素为对象的数组,把其中所有对象的属性,都合并进一个新的对象中。

在我的经历中,这样的业务场景还没遇到过。盲猜可以用来合并多个对象?

26. noop

知空函数,是用来干嘛的呢?

27. no

一直返回false的函数。

28. identity

返回参数本身。

29. genStaticKeys

将入参 modules 数组每一项的 staticKeys 合并为同一个数组并转成字符串后返回。

入参 modules 是需要编译的模块。

30. looseEqual

宽松相等。

JS中引用类型是否相等是通过引用地址来对比的。当想知道两个对象是否具有相同内容时,可以使用此方法。也是一般所说的 JS 深比较。通过递归对比所有属性是否内容相同来比较。

31. looseIndexOf

JS 中的 indexOf 方法用于查找一个值在数组中的位置。判断该值和数组中对应值是否相等时,是使用严格比较,也就是说如果是引用类型,将对比引用地址而不是具体内容。

在此方法中,使用 looseEqual 方法进行对比值的内容是否相同,不是浅比较而是深比较。

32. once

利用闭包特性,确保传入的函数只执行一次。

33. 枚举s

最后面是一些vue2中用到常量的枚举。

可以看到 vue2 中对低版本做了比较多的兼容,写了很多 polyfill 。

利用闭包特性实现了很多方法。