[译] 纯 JavaScript 版本的 Lodash 数组 Filtering 和 Manipulation 方法

原文转载自 「掘金掘金翻译计划」 ( https://juejin.im/post/5ec614196fb9a047b46b14f3 ) By 子非

预计阅读时间 0 分钟(共 0 个字, 0 张图片, 0 个链接)

纯 JavaScript 版本的 Lodash 数组 Filtering 和 Manipulation 方法

Photo by [Nathan Dumlao](https://unsplash.com/@nate_dumlao?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

Lodash 是一个十分有用的工具库,它能让我们轻松地处理对象和数组。

而现在 JavaScript 标准库正在追赶 Lodash 这样的库,我们可以用简单的方法实现很多功能。

我们可以用纯 JavaScript 轻松实现 pullAllBypullAllWithpullAtremove 方法。

pullAllBy

pullAllBy 会返回一个数组,此数组会先通过 iteratee 函数转换元素,然后通过给定值匹配来移除我们想移除的元素。

我们按如下方式来实现:

const pullAllBy = (arr, values, iteratee) => arr.filter(a => !values.map(iteratee).includes(iteratee(a)))
复制代码

上面的代码中,在使用 includes 对比之前调用给定的 iteratee 函数获得对应的值。并且在 includes 中也调用 iteratee 做同样的转换来让值能正确地对比。

然后我们可以按如下方法使用我们的 pullAllBy

const result = pullAllBy([1, 2.1, 3], [2.2, 3], Math.floor)
复制代码

result 得到 [1]

pullAllWith

Lodash 的 pullAllWith 方法需要一个比较器来比较然后排除值,而非用 iteratee 先转换再比较。

举一个例子,我们可以按如下方法实现:

const pullAllWith = (arr, values, comparator) => arr.filter(a => values.findIndex((v) => comparator(a, v)) === -1)
复制代码

上面的代码中,使用纯 JavaScript 中的带回调函数的 findIndex 方法,此方法调用回调函数 comparator 来比较值。

我们调用 filter 来过滤出 values 数组包含的元素。

下面可以按如下方法调用:

const result = pullAllWith([1, 2, 3], [2, 3], (a, b) => a === b)
复制代码

result 得到 [1]

pullAt

Lodash 的 pullAt 方法返回一个数组,此数组的元素通过给定的索引来得到。

它同时会在数组中移除这些索引对应的元素。

我们再一次使用 filter 方法来过滤出我们想要的元素,方法如下:

const pullAt = (arr, indexes) => {
  let removedArr = [];
  const originalLength = arr.length
  for (let i = 0; i < originalLength; i++) {
    if (indexes.includes(i)) {
      removedArr.push(arr[i]);
    }
  }

  for (let i = originalLength - 1; i >= 0; i--) {
    if (indexes.includes(i)) {
      arr.splice(i, 1);
    }
  }
  return removedArr.flat()
}
复制代码

在上面的代码中,我们使用 for 循环遍历数组,并用给定的 indexes 数组调用 includes 对元素们做判断。

然后我们把要被移除的元素推送到 removedArr 数组中。

之后我们的第二个循环会反向遍历 arr,这样在我们调用 splice 时不会改变 arr 在当前 i 以前部分的索引。

在循环中,我们只用调用 splice 来移除给定索引的元素。

最终,我们调用 flat 来对数组做扁平化处理,因为 splice 会返回一个数组。

因此,当我们像下面这样调用它时:

const arr = [1, 2, 3]
const result = pullAt(arr, [1, 2])
复制代码

我们可以看到 result[2, 3],因为指定数组中的 [1, 2] 索引对应的元素要被删除,并且由于索引 0 的元素是唯一没有被移除的,所以 arr 现在是 [1]

Photo by [Tim Mossholder](https://unsplash.com/@timmossholder?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

remove

remove 方法移除满足给定条件的元素并且返回被移除的元素。

我们自己可以向下面这样来用 for 循环来实现它:

const remove = (arr, predicate) => {
  let removedArr = [];
  const originalLength = arr.length
  for (let i = 0; i < originalLength; i++) {
    if (predicate(arr[i])) {
      removedArr.push(arr[i]);
    }
  }
  for (let i = originalLength - 1; i >= 0; i--) {
    if (predicate(arr[i])) {
      arr.splice(i, 1);
    }
  }
  return removedArr.flat();
}
复制代码

在上文的代码中,我们的 pullAt 方法有两次循环。然而现在我们用 predicate 函数,而不是用数组索引来检查。。

就像 pullAt 一样,我们必须反向遍历数组来防止在循环 arrsplice 改变索引。

然后,当我们像下面这样调用它时:

const arr = [1, 2, 3]
const result = remove(arr, a => a > 1)
复制代码

result 的值是 [2, 3] 并且 arr[1],因为我们指定 predicatea => a > 1,所以任何比 1 大的元素都会被移除,返回剩下的值。

总结

pullAtremove 非常相似,除了 pullAt 接收一组索引而 remove 接收一个指定条件的回调函数。

pullAllBypullAllWith 都使用 filter 方法实现。pullAllBy 在对比之前使用 iteratee 来预处理元素。

如果发现译文存在错误或其他需要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 本文永久链接 即为本文在 GitHub 上的 MarkDown 链接。


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

more_vert