本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。
前言
- 这是跟随@若川 源码活动的第二个打卡。
- 该期活动地址【若川视野 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) { |