前言
本文参加了由公众号@若川视野 发起的每周源码共读活动。从简单到进阶学习源码中的巧妙之处,旨在于将学习的东西应用到实际的开发中,同时借鉴源码中的思想,规范自我开发,以及锻炼自己的开发思维。也欢迎大家加入大佬的源码共读活动。一起卷起来。
正文
vue2的源码中在src./shared/utils.js中包含着基础的工具函数
1、Object.freeze({}) 冻结对象
const emplyobject=Object.freeze({})//冻结对象,该方法只能冻结对象的第一层属性,如果想实现整个对象的冻结,可以对于多层级的对象想要进行每个属性的冻结的话这要通过遍历的方式去进行。
Object.isFrozen(emplyobject) //进行判断是否是冻结对象
2.isUndef() 是否是未定义变量
function isUndef(v){
return v === undefined || v === null
}
3.isdef() 是否定义
function isdef(v){
return v !== undefined || v !== null
}
4.isTrue 是否为真
function isTrue(v){
return v===true
}
5.isFalse 是否为假
function isFalse(v){
return v === false
}
6.isPrimate() 是否为原始类型
function isPrimate(v){
return typeof v ==='string' || typeof v==='number' || typeof v === 'boolean' || typeof v ==='symbol'
}
7.isObject 是否是对象
function isObject(v){
return v!==null && typeof === 'object'
}
//因为null 的typeof类型也是object
//typeof 可以判断出数据类型,判断出的类型有 string,undefinde,number,boolean,symbol,function
8.isPlainObject() 判断是否是纯函数
function isPlainObject(v){
return Object.prototype.toString.call(v)==="[object Object]"
}
//通过typeof 判断的null array {} 等复杂的数据类型都是object类型 因此我们通过toString()的方法可以获取到对应的字符串类型.
9.isRegExp() 判断是否是正则
function isReqExp(){
return Object.prototype.toString.call(v)==="[object RegExp]"
}
10.isPromise 判断是否是promise
function isPromise(v){
return isDef(v)&& typeof v.then ==='function'&&typeof v.catch === 'function'
}
11.toString() 转成字符串
function toString(v){
return v==null?"":Array.isArray(v)||(isPlainObject(v)&&val.toString=Object.prototype.toString)?JSON.stringify(v,null,2):String(v)
}
//对于JSON.stringify的深入理解:
JSON.stringify 中的第二个参数有两种类型:
1.函数
函数接受连个参数 参数1则是key 参数2则是value 值 第一次获取的key是空 value 则是要转换的数据 后续则正常对应,
2.数组
则只会转换数组中包含的key
第三个参数则是 转成字符传后 每个值的偏移量 可以理解成缩进
12.toNumber() 转数字
function toNumber(v){
const n = parseFloat(v)
return isNaN(n)?v:n
}
13 makeMap()生成map 对象 并且返回一个用于检测map对象中共是否包含特定key的函数 ,第二个参数则是小写选项
function makeMap(str,expectsLowecase){
const list = str.split(',')
//创建空对象
const obj = Object.create(null)
for(let i =0 ;i <list.length;i++){
obj[list[i]]=true
}
return expectsLowecase?function(v){
return obj[v.toLowerCase()]
}:function(v){
return obj[val]
}
}
14 .reomve() 数组中移除某一项
function remove(arr){
if (arr.length) {
const index = arr.indexOf(item)
if (index > -1) {
return arr.splice(index, 1)
}
}
}
//有个性能的问题 一般数组的这个中删除的操作 很浪费性能 有一种方法就是将要删除的项修改成 null 再通过判断null 然后中其他逻辑
15.hasOwn 判断是否是自己的属性
function hasOwm(object,key){
const hasOwnProperty = Object.prototype.hasOwnProperty
return hasOwnProperty.call(object,key)
}
16. cached 利用闭包缓存
function cached(fn){
const cache = Object.create(null)
return function(str){
const hit = cache[str]
return hit?hit:(cache[str]=fn(str))
}
}
17,toArray() 类数组,对象转数组
function toArray(list,start=0){
//获取截取转换的个数
let i=list.length-start
const arr= new Array(i)
while(i--){
//采用倒序的方式赋值
arr[i]=list[i+start]
}
return arr
}
18. extend对象属性混合
```js
function extend(to,_from){
for(const key in from){
to[key]=_from[key]
}
}
```
19. toObject 数组对象转对象
```js
function toObject(arr){
const res ={}
for(let i =0;i<arr.length;i++){
if(arr[i]){
extend(res,arr[i])
}
}
return res
}
```
20.camelize 连字符转驼峰
var camelizeRE = /-(\w)/g;
var camelize = cached(function (str) {
return str.replace(camelizeRE, function (_, c) { return c ? c.toUpperCase() : ''; })
});
/// \w 则匹配的是 字母数字和下滑线
//replace() 第一个参数则是匹配的规则也就是要替换的值,第二个参数有两种类型
1.字符串
如果是字符串的话则直接进行替换
2.如果是函数的话则函数的第一个参数则是匹配到的值 第二个参数是匹配值的子串
21.capitalize 首字符转大写
function capitalize(str){
return str.charAt(0).toUpperCase()+str.slice(1)
}
22.驼峰转连字符
var hyphenateRE = /\B([A-Z])/g;
var hyphenate = cached(function (str) {
return str.replace(hyphenateRE, '-$1').toLowerCase()
});
\B 表示非边界的字符
23. once 确保函数只执行一次
function once (fn) {
var called = false;
return function () {
if (!called) {
called = true;
fn.apply(this, arguments);
}
}
}
24.looseEqual 宽松相等
由于数组和对象这种复杂的数据类型,看起来内容相等,
const a ={}
const b={}
a===b //false
a==b //false
所以该函数是对数组,对象进行递归对比,如果内容完全相等则宽松相等。
function looseEqual (a, b) {
if (a === b) { return true }
var isObjectA = isObject(a);
var isObjectB = isObject(b);
if (isObjectA && isObjectB) {
try {
var isArrayA = Array.isArray(a);
var isArrayB = Array.isArray(b);
if (isArrayA && isArrayB) {
return a.length === b.length && a.every(function (e, i) {
return looseEqual(e, b[i]) }) }
else if (a instanceof Date && b instanceof Date) {
return a.getTime() === b.getTime()
} else if (!isArrayA && !isArrayB) {
var keysA = Object.keys(a);
var keysB = Object.keys(b);
return keysA.length === keysB.length && keysA.every(function (key) {
return looseEqual(a[key], b[key]) }) } else {
/* istanbul ignore next */ return false } } catch (e) {
/* istanbul ignore next */ return false }
} else if (!isObjectA && !isObjectB) {
return String(a) === String(b)
} else {
return false
} }
总结
在工具函数的学习不仅掌握了 一些常用的工具函数的编写,同时还掌握了正则表达式,以及常用api的特殊使用方式。最后继续学习源码,继续卷。下一篇[axios中的工具函数]