源码学习——lodash(八)

1,015 阅读3分钟

前言

本节我们来学习一下lodash中pull系列方法的源码,该方法是用来过滤数组,处理掉数组中不想要的数据。

pull与pullAll

pull会过滤掉数组中与给定值相同的数据,该方法会改变原数组。具体的语法为:

pull(array,values)
//array 数组 values 过滤的值
const arr = [1,1,2,3]
_.pull(arr,1,2)
console.log(arr) // [3]

pullAll方法跟pull用法是一样的,具体的区别在于pullAll的第二个参数为一个数组

_.pull(arr,[1,2])

两者的区别也意味着源码差别不大,打开源码我们就会发现pull的源码就是用pullAll的方法:

QQ图片20240509233452.png
注意这里values用了扩展运算符进行展开,是一种常见的用法,该用法只能放到最后一位参数。接下来我们直接看pullAll的源码: QQ图片20240509234243.png
核心方法为basePullAll,该方法我们放到后面进行解析。

pullBy与pullWith

系列方法名称的含义都是一样的,By表示迭代;with表示比较。上面两种方法就是在pullAll的基础上增加了迭代函数与比较函数。

pullAllBy(array, values, iteratee)
pullAllWith(array, values, comparator)
const arr = [1,2.1]
_.pullAllBy(arr,[2],Math.floor)
console.log(arr) // [1]
_.pullAllWith(arr,[1],_.isEqual)
console.log(arr) // [2.1]

上面两个方法的源码区别就在于basePullAll的调用:

//pullBy
basePullAll(array, values, iteratee)
//pullWith
basePullAll(array, values, undefined, comparator)

下面我们就来看下basePullAll的源码: QQ图片20240509235811.png

  • 参数判断。四个参数用来兼容不同的方法,注意indexOf方法根据comparator参数进行了判断,该方法用来查找下标。
  • 数据处理。如果是By方法就用iteratee处理array得到seen,如果array与values相同会用copyArray将valuesy复制一下:
    image.png
    用while重新赋值达到复制目的。
  • 第一层while通过index循环参数数组values,这里条件写的很简便,直接用++达到循环目的。通过下标拿到value值,如果是By就用iteratee函数进行处理得到computed。
  • 第二次while通过fromIndex循环数组array,利用indexOf方法获取在seen数组中跟computed相等值的下标,该方法我们之前解析过就不再赘述。
  • 最后通过splice方法删除满足条件的元素,seen与array的判断是为了兼容By方法。
    由此看来pull系类方法核心思路就是通过两次循环将values与array的值进行一个个对比,当values的值在array中存在就将其去除。

pullAt

pullAt根据下标去掉array中对应的元素,并返回去掉的元素组成的数组,该方法会改变原数组。

pullAt(array,indexs)
//array 数组 indexs 过滤的下标
const arr = [1,2,3]
_.pullAt(arr,1)
console.log(arr) // [1,3]
console.log(_.pullAt(arr,1))//[2]

虽然它是pull开头但是效果跟前面几个完全不同,下面就看下该方法的源码。

QQ图片20240510205649.png
该方法运用到了两个基础方法一个baseAt用来返回reuslt,一个basePullAt用来处理array。首先我们来看下baseAt:

QQ图片20240510212713.png
注意这里参数为Object与paths表示对象与key值数组,当然数组也是符合的。baseAt思路很简单就是通过循环下标数组然后将数组对应下标的值添加到result中。 接下来我们看下basePullAt方法:

QQ图片20240510213238.png

  • 获取循环要素length与lastIndex,通过length循环下标数组
  • 循环条件有两个,length===lastIndex首次循环生效,为什么会有index !== previous呢?previous只是声明未定义所以刚开始是undefined,所以该条件是非空判断index。注意当length为0时循环结束
  • 最后再判断下index,兼容数组与对象。index是下标说明是数组就会使用splice清除,否则就会用baseUnset去除。
    pullAt比起pull系列方法要复杂一点,特别是basePullAt需要花一点时间去理解。

总结

以上就是pull方法的源码解读,lodash循环判断的表达式都是简便有用的,值得我们学习。