从易到难读源码。
今天读的源码是 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 。
利用闭包特性实现了很多方法。