本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。
前言
- 这是跟随@若川 源码活动的第二个打卡。
 - 该期活动地址【若川视野 x 源码共读】第24期 | vue2工具函数
 
工具函数
1. emptyObject
1  | /*!  | 
Object.freeze()方法可以冻结一个对象,冻结指的是不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。也就是说,这个对象永远是不可变的。该方法返回被冻结的对象。
1  | var deadline = Object.freeze({date: 'yesterday'});  | 
2. isUndef
判断是否是未定义
1  | // These helpers produce better VM code in JS engines due to their  | 
3. isDef
判断是否已经定义
1  | // These helpers produce better VM code in JS engines due to their  | 
4. isTrue
1  | function isTrue (v) {  | 
5. isFalse
1  | function isFalse (v) {  | 
6. isPrimitive
判断值是否是原始值
1  | /**  | 
7. isObject
判断是否是对象,没有区分对象和数组
1  | /**  | 
8. toRowType
转换成原始类型
1  | var _toString = Object.prototype.toString;  | 
为什么需要.slice(8, -1)
- _toString.call(value) 生成结果[object String] 。
 - 二、vue-shared.md __toString.call(value).slice(8, -1) 去掉[object和]。
 
9. isPlainObject
判断是否是纯对象
1  | function isPlainObject (obj) {  | 
10. isRegExp
判断是否是正则表达式
1  | function isRegExp(obj) {  | 
11. isValidArrayIndex
判断是否是可用的数组索引值
1  | function isValidArrayIndex(val) {  | 
为什么要使用parseFloat?
使用parseFloat可解析其他进制字符串时,有可能由于计算精度问题无法得到一个确定的十进制证书。
为什么使用isFinite
is Finite()函数判断被传入的参数值是否为一个有限数值。
1
2
3
4
5
6
7
8
9
10isFinite(Infinity); // false
isFinite(NaN); // false
isFinite(-Infinity); // false
isFinite(0); // true
isFinite(2e64); // true
isFinite('0'); // true
Number.isFinite('0') // false
Number.isFinite(null) // false
12. isPromise
判断是否是promise
1  | funciton isPromise(val) {  | 
13. toString转字符串
1  | let _toString = Object.prototype.toString;  | 
数组或者对象并且对象的
toString方法是Object.prototype.toString,用JSON.stringify转换JSON.stringify(val, null, 2)
JSON.stringify(value, replacer, space)
value序列化为一个JSON字符串的值replacer如果该参数是一个函数,则在序列化过程中,被序列化的值的每个属性都会经过该函数的转换和处理;如果该参数是一个数组,则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中;如果该参数为 null 或者未提供,则对象所有的属性都会被序列化。space指定缩进用的空白字符串,用于美化输出(pretty-print);如果参数是个数字,它代表有多少的空格;上限为10。该值若小于1,则意味着没有空格;如果该参数为字符串(当字符串长度超过10个字母,取其前10个字母),该字符串将被作为空格;如果该参数没有提供(或者为 null),将没有空格。
例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15function replacer(key, value) {
if (typeof value === "string") {
return undefined;
}
return value;
}
var foo = {
foundation: "Mozilla",
model: "box",
week: 45,
transport: "car",
month: 7
};
var jsonString = JSON.stringify(foo, replacer);// {week: 45, month: 7}
14. toNumber
转数字
1  | function toNumber(val) {  | 
15. makeMap生成一个map
传入一个以逗号分隔的字符串,生成一个map,并且返回一个函数检测key值在不在这个map中。第二个参数是小写选项。
1  | // 传入一个以逗号分隔的字符串,生成一个 map(键值对) ,并且返回一个函数检测 key 值在不在这个 map 中。第二个参数是小写选项。  | 
16. isBuiltInTag
判断是否是内置的Tag
1  | var isBuiltInTag = makeMap('slot, component', true);  | 
17. isReservedAttribute
判断是否是保留的属性
1  | let isReservedAttribute = makeMap('key,ref,slot,slot-scope,is');  | 
18. remove
移除数组中的某一项
1  | function remove(arr, item) {  | 
splice其实是一个很耗性能的方法。删除数组中的一项,其他元素都要移动位置。引申:
axios InterceptorManager拦截器源码 中,拦截器用数组存储的。但实际移除拦截器时,只是把拦截器置为null。而不是用splice移除。最后执行时为null的不执行,同样效果。axios拦截器这个场景下,不得不说为性能做到了很好的考虑。因为拦截器是用户自定义的,理论上可以有无数个,所以做性能考虑是必要的。看如下
axios拦截器代码示例:
 1
2
3
4
5
6
7
8
9
10
11
12
13
14 // 代码有删减
// 声明
this.handlers = [];
// 移除
if (this.handlers[id]) {
this.handlers[id] = null;
}
// 执行
if (h !== null) {
fn(h);
}
19. hasOwn
检测是否是自己的属性
1  | var hasOwnProperty = Object.prototype.hasOwnProperty;  | 
20. cached
缓存
1  | function cached (fn) {  | 
21. camelize
连字符转小驼峰 如 on-click => onClick
1  | var camelizeRE = /-(\w)/g;  | 
\w 表示 [0-9a-zA-Z_]。表示数字、大小写字母和下划线。
```javascript
String.prototype.replace(regexp | substr, newSubStr|function)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
我们来重点看一下第二个参数中的`function` 中的参数
[MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/replace#%E6%8C%87%E5%AE%9A%E4%B8%80%E4%B8%AA%E5%87%BD%E6%95%B0%E4%BD%9C%E4%B8%BA%E5%8F%82%E6%95%B0)
- `match`
- `p1,p2, ...` 假如replace()方法的第一个参数是一个[`RegExp`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp) 对象,则代表第n个括号匹配的字符串。如果是用 `/(\a+)(\b+)/` 这个来匹配,`p1` 就是匹配的 `\a+`,`p2` 就是匹配的 `\b+`。
> 因此,在这里,_ 的值是 -c, c 的值 是 c
- ...
# 22. capitalize
> 首字母转大写
```javascript
var capitalize = cached(function (str) {
return str.charAt(0).toUpperCase() + str.slice(1);
})
23. hyphenate
小驼峰转连字符 onClick => on-click
1  | var hyphenateRE = /\B([A-Z])/g;  | 
24. polyfillBind
bind垫片 兼容了老版本浏览器不支持原生的bind函数。同时兼容写法,对参数的多少做出了判断,使用call和apply实现。
1  | function polyfillBind(fn, ctx) {  | 
25. toArray
把类数组转成真正的数组, 支持从指定位置开始转化,默认从0开始。
1  | function toArray(list, start) {  | 
26. extend
合并对象
1  | function extend(to, _from) {  | 
27. toObject
转对象, 传入的是个数组,后面的元素会覆盖前面的元素
1  | function toObject(arr) {  | 
28. noop
空函数
1  | function noop(a, b, c) {}  | 
29. no
一直返回false
1  | var no = function(a, b, c) { return false; };  | 
30. identity
返回参数本身
1  | var identity = function(_) { return _; };  | 
31. genStaticKeys
生成静态属性
1  | function genStaticKeys (modules) {  | 
32. looseEqual
宽松相等
由于数组、对象等是引用类型,所以两个内容看起来相等,严格相等都是不相等。
1  | var a = {};  | 
所以该函数是对数组、日期、对象进行递归比对。如果内容完全相等则宽松相等。
1  | function looseEqual(a, b) {  | 
33. looseIndexOf
宽松的in de x O f
1  | function looseIndexOf(arr, val) {  | 
34. once
利用闭包特性,存储状态,实现函数只执行一次
1  | function once(fn) {  |