lodash 起步(数组)

Lodash 是一个较为流行的 JavaScript 的实用工具库。

在开发过程中如果能熟练使用一些工具库提供的方法,有利于提高开发效率

笔者从 API 上入手,不分析其源码,先从全局的角度来体验、研究它。分析 API 的命名特性、哪些方法有用,哪些又是比较鸡肋,仅代表笔者个人意见。

Tip:根据Lodash 中文文档得知,API 主要分为:数组、集合、函数、语言、数学、数字、对象、Seq、字符串、实用函数等约10个部分。而数组在我们编程过程中具有非常重要的地位,故笔者决定先从其入手。

环境准备

直接通过引用 bootstrap 免费的 cdn 的方式进行,只需两个文件:index.htmltest-array.js。内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.js"></script>
<script src="./test-array.js"></script>
</head>
<body> </body>
</html>
let r

// 封装 console.log,使之更剪短
const l = (...ops) => {
console.log(...ops)
} {
r = _.VERSION
// => 4.17.21
l(r)
} {
r = _.join(['a', 'b', 'c'], '~');
// => 'a~b~c'
l(r)
}

Tip: 所有测试都是如上结构

api 设计特性分析

  1. 有的方法可能是考虑兼容性,比如 _.fill,但 javascript 也有对应的原生方法(Array.prototype.fill),倘若使用 babel 库帮忙转换,那这类方法就有些鸡肋
  2. 命名系列化。比如下文的 _.sortedIndex 系列,有 .sortedIndex、.sortedIndexOf、.sortedLastIndexOf、.sortedIndexBy、.sortedLastIndex、.sortedLastIndexBy 共6个,核心是 _.sortedIndex,通常系列方法有功能增强版,例如这里的 _.sortedIndexBy,而命名中有 Last 通常从后往前查找
  3. 系列化的 api 通常有基础版和加强版。例如 _.difference 系列,_.differenceBy_.differenceWith都是加强版
  4. 提供简写进一步提高代码简洁性,比如下面的 _.isEqual
const objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
_.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual);
// => [{ 'x': 2, 'y': 1 }]

数组 api 总览

仅列出非鸡肋方法:

Tip: 笔者认为可以用原生方法非常便捷的替换的 api 就是鸡肋。

  • _.chunk - 分块。将数组(array)拆分成多个 size 长度的区块,并将这些区块组成一个新数组
  • _.compact - 压紧。创建一个新数组,包含原数组中所有的非假值元素
  • _.difference 系列 - 。从第一个数组中排除给定数组中的值
  • _.drop 系列 - 减小。例如去除数组前面两个元素
  • _.fromPairs/_.toPair - 一双。例如 [['fred', 30], ['barney', 40]] <---> { 'fred': 30, 'barney': 40 }
  • _.intersection 系列 - 交集
  • _.pull - 移除数组中的值
  • _.sortedIndex - value 应插入已排序数组中的索引
  • _.sortedUniq - 唯一。对已排序的数组过滤重复值
  • _.take - 切片(从左提取 n 个元素)
  • _.union - 并集
  • _.uniq - 唯一(用于去重)
  • _.zip - 压缩[1, 2], [10, 20], [100, 200] -> [[1, 10, 100], [2, 20, 200]]
  • _.unzip 系列 - 类似 _.zip。[[1, 2], [10, 20], [100, 200]] -> [[1, 10, 100], [2, 20, 200]]
  • _.without - 缺乏。可用 array.filter 替代。
  • _.xor 系列 - X集。只存在于某个数组中的值。

数组 api 详细

_.chunk

_.chunk - 分块。

// _.chunk(array, [size=1]) - 将数组(array)拆分成多个 size 长度的区块,并将这些区块组成一个新数组。 如果array 无法被分割成全部等长的区块,那么最后剩余的元素将组成一个区块。
{
r = _.chunk(['a', 'b', 'c', 'd'], 2)
// => [['a', 'b'], ['c', 'd']]
l(r) r = _.chunk(['a', 'b', 'c', 'd'], 3)
// => [['a', 'b', 'c'], ['d']]
l(r)
}

_.compact

_.compact - 压紧。可用 array.filter 实现

// _.compact(array) - 创建一个新数组,包含原数组中所有的非假值元素。例如false, null,0, "", undefined, 和 NaN 都是被认为是“假值”。
{
// 返回过滤掉假值的新数组
// 例如 false, null, 0, "", undefined, NaN 都是被认为是“假值”
r = _.compact([false, null, 0, "", undefined, NaN, 1]);
// => [1]
l(r) // 可用 array.filter 实现
r = [false, null, 0, "", undefined, NaN, 1].filter(v => !!(v))
// => [1]
l(r)
}

_.difference 系列

_.difference系列 - 差(从第一个数组中排除给定数组中的值)。_.differenceBy_.differenceWith都是加强版。

// _.difference(array, [values]) - 创建一个具有唯一array值的数组,每个值不包含在其他给定的数组中
// _.differenceBy(array, [values], [iteratee=_.identity]) - 这个方法类似_.difference ,除了它接受一个 iteratee (注:迭代器), 调用array 和 values 中的每个元素以产生比较的标准。
// _.differenceWith(array, [values], [comparator]) - 这个方法类似_.difference ,除了它接受一个 comparator (注:比较器),它调用比较array,values中的元素。 结果值是从第一数组中选择
{ // 从第一个数组中排除给定数组中的值。
// 注:非数组会忽略
r = _.difference([1, 2, 3, 4, 5, 6], [1, 2], [3], [4], 5, [6])
// 5
l(r) // 与 difference 类似。不同之处是每个值得调用 Math.floor 在比较,比如 2.2 和 2.5 认为是相等的
r = _.differenceBy([3.1, 2.2, 1.3], [4.4, 2.5], Math.floor);
// => [3.1, 1.3]
l(r) // The `_.property` iteratee shorthand.
r = _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');
// => [{ 'x': 2 }]
l(r) var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
// 与 difference 类似。不同之处是每个值得调用 _.isEqual 这个比较器
// 与 differenceBy 区别,感觉前者是迭代每个值并从中取得值进行比较,而 differenceWith 直接用比较器直接比较
r = _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual);
// => [{ 'x': 2, 'y': 1 }]
l(r)
}

_.drop 系列

_.drop系列 - 减小(例如去除数组前面两个元素)。某些场景可以使用 ... 结构语法替换;_.dropRightWhile_.dropWhile 都是增强版。

// _.drop(array, [n=1]) - 创建一个切片数组,去除array前面的n个元素。(n默认值为1。)
// _.dropRight(array, [n=1]) - 创建一个切片数组,去除array尾部的n个元素。(n默认值为1。)
// _.dropRightWhile(array, [predicate=_.identity]) - 创建一个切片数组,去除array中从 predicate 返回假值开始到尾部的部分
// _.dropWhile(array, [predicate=_.identity]) - 创建一个切片数组,去除array中从起点开始到 predicate 返回假值结束部分
{
// 去除前面两个元素
r = _.drop([1, 2, 3], 2);
// => [3]
l(r); // 用...解构语法替代上面例子
[, , ...r] = [4, 5, 6]
// => [6]
l(r) // 去除后面两个元素
r = _.dropRight([1, 2, 3], 2);
// => [1]
l(r) // 作用难以理解。直接用 filter
var users = [
{ 'user': 'barney', 'active': true },
{ 'user': 'fred', 'active': false },
{ 'user': 'pebbles', 'active': false }
]; r = _.dropRightWhile(users, function (o) { return !o.active; });
// => [{ 'user': 'barney', 'active': true }]
l(r)
}

_.fromPairs & _.toPair

_.fromPairs & _.toPair - 一双。前者可用 array.reduce 实现,后者可用 Object.entries 方便的替代。

// _.fromPairs(pairs) - 与_.toPairs正好相反;这个方法返回一个由键值对pairs构成的对象。
{
let arr = [['fred', 30], ['barney', 40]]
r = _.fromPairs(arr);
// => { 'fred': 30, 'barney': 40 }
l(r) // 用 reduce 重写上述例子
r = arr.reduce((obj, [key, value]) => {
obj[key] = value
return obj
}, {})
// => {fred: 30, barney: 40}
l(r) r = _.toPairs(r)
// => [['fred', 30], ['barney', 40]]
l(r) // 用 Object.entries() 重写上一个示例
r = { fred: 30, barney: 40 }
// Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组
r = Object.entries(r)
// => [['fred', 30], ['barney', 40]]
l(r)
}

_.intersection 系列

_.intersection - 交集。_.intersectionBy_.intersectionWith 是增强版。

// _.intersection([arrays]) - 数组的交集
// _.intersectionBy([arrays], [iteratee=_.identity]) - 这个方法类似_.intersection,区别是它接受一个 iteratee 调用每一个arrays的每个值以产生一个值,通过产生的值进行了比较
// _.intersectionWith([arrays], [comparator]) - 这个方法类似_.intersection,区别是它接受一个 comparator 调用比较arrays中的元素。结果值是从第一数组中选择
{
r = _.intersection([1, 2], [2, 3], [2, 3, 4]);
// => [2]
l(r) r = _.intersection([1, 2], [3, 4]);
// => []
l(r) r = _.intersectionBy([2.1, 1.2], [4.3, 2.4], Math.floor);
// => [2.1]
l(r) const objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
const others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; r = _.intersectionWith(objects, others, _.isEqual);
// => [{ 'x': 1, 'y': 2 }]
l(r)
}

_.pull 系列

_.pull - 移除数组中的值。_.pullAt 根据索引移除,_.pullAll 系列都是加强版。某些场景可使用 array.filter 替代。

// _.pull(array, [values]) - 移除数组array中所有和给定值相等的元素,使用SameValueZero 进行全等比较
// _.pullAll(array, values) - 这个方法类似_.pull,区别是这个方法接收一个要移除值的数组。
// _.pullAllBy(array, values, [iteratee=_.identity]) - 这个方法类似于_.pullAll ,区别是这个方法接受一个 iteratee(迭代函数) 调用 array 和 values的每个值以产生一个值,通过产生的值进行了比较。
// _.pullAllWith(array, values, [comparator]) - 这个方法类似于_.pullAll,区别是这个方法接受 comparator 调用array中的元素和values比较。
// _.pullAt(array, [indexes]) - 根据索引 indexes,移除array中对应的元素,并返回被移除元素的数组。Tip:删除非连续的多个则不方便用 array.splice 替代
{
r = [1, 2, 3, 1, 2, 3]
_.pull(r, 2, 3);
l(r)
// => [1, 1] // 用 array.filter 重写上一个示例
r = [1, 2, 3, 1, 2, 3];
r = r.filter(item => item !== 2 && item !== 3)
// => [1, 1]
l(r) // 数组中移除 { 'x': 3, 'y': 4 }
r = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }];
_.pullAllWith(r, [{ 'x': 3, 'y': 4 }], _.isEqual);
// => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }]
l(r) // 移除索引 1 和 3。
r = [5, 10, 15, 20];
_.pullAt(r, 1, 3);
// => [5, 15]
l(r)
}

_.sortedIndex 系列

_.sortedIndex - value 应插入已排序数组中的索引。 _.sortedIndexBy 是增强版。_.sortedIndexOf[鸡肋] 和 array.indexOf 类似。

:数组要已排序,否则得不到预期值。

// _.sortedIndex(array, value) - 使用二进制的方式检索来决定 value值 应该插入到数组中 尽可能小的索引位置,以保证array的排序。
// _.sortedIndexOf(array, value) - 这个方法类似_.indexOf,除了它是在已经排序的数组array上执行二进制检索。
// _.sortedLastIndexOf(array, value) - 这个方法类似_.lastIndexOf
// _.sortedIndexBy(array, value, [iteratee=_.identity]) - 这个方法类似_.sortedIndex
// _.sortedLastIndex(array, value) - 此方法类似于_.sortedIndex
// _.sortedLastIndexBy(array, value, [iteratee=_.identity]) - 这个方法类似_.sortedLastIndex
{
// 数组有序,40 所放索引正确
r = _.sortedIndex([20, 30, 50], 40)
// => 2
l(r) // 数组无序,笔者自己都不知道 40 应放哪里
r = _.sortedIndex([50, 20, 30], 40)
// => 3
l(r) r = [{ 'x': 4 }, { 'x': 5 }];
r = _.sortedIndexBy(r, { 'x': 4.5 }, function (o) { return o.x; });
// => 1
l(r) // 和 array.indexOf 类似
r = _.sortedIndexOf([4, 5, 5, 5, 6], 5);
// => 1
l(r) r = [4, 5, 5, 5, 6].indexOf(5)
// => 1
l(r) // _.sortedLastIndex(array, value) - 和 array.lastIndexOf() 类似
}

_.sortedUniq 系列

_.sortedUniq - 唯一。对已排序的数组过滤重复值,可用 Set 过滤。_.sortedUniqBy 是增强版

// _.sortedUniq(array) - 这个方法类似_.uniq,除了它会优化排序数组。
// _.sortedUniqBy(array, [iteratee]) - 这个方法类似_.uniqBy,除了它会优化排序数组。
{
r = _.sortedUniq([1, 1, 2]);
// => [1, 2]
l(r) // 用 Set 过滤重复值
r = [...new Set([1, 1, 2])]
// => [1, 2]
l(r) r = _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor);
// => [1.1, 2.3]
l(r) // 利用一个临时数组实现上一个示例
r = [1.1, 1.2, 2.3, 2.4]
const tmp = []
r = r.filter(item => {
let v = Math.floor(item)
if (tmp.includes(v)) {
return false
}
tmp.push(v)
return true
})
// => [1.1, 2.3]
l(r)
}

_.take 系列

_.take - 切片(从左提取 n 个元素)。_.take 和 _.takeRight 可用 array.slice 替代。 _.takeWhile 是增强版。

// _.take(array, [n=1]) - 创建一个数组切片,从array数组的起始元素开始提取n个元素。
// _.takeRight(array, [n=1]) - 创建一个数组切片,从array数组的最后一个元素开始提取n个元素。
// _.takeWhile(array, [predicate=_.identity]) - 与 _.takeRightWhile 类似,只是方向不同
// _.takeRightWhile(array, [predicate=_.identity]) - 从array数组的最后一个元素开始提取元素,直到 predicate 返回假值
{
r = _.take([1, 2, 3], 2);
// => [1, 2]
l(r) // 可用 array.slice 重写上一个示例
r = [1, 2, 3].slice(0, 2)
// => [1, 2]
l(r) r = _.takeRight([1, 2, 3, 4], 2);
// => [3, 4]
l(r) // 可用 array.slice 重写上一个示例
r = [1, 2, 3, 4].slice(-2)
// => [3, 4]
l(r) const users = [
{ 'user': 'barney', 'active': true },
{ 'user': 'fred', 'active': false },
{ 'user': 'pebbles', 'active': false }
];
r = _.takeRightWhile(users, function (o) { return !o.active; });
// => objects for ['fred', 'pebbles']
l(r) // 自己实现 _.takeRightWhile
r = []
users.reverse().forEach(item => {
if (item.active) {
return false
}
r.push(item)
})
r.reverse()
// => objects for ['fred', 'pebbles']
l(r)
}

_.union 系列

_.union - 并集。_.union 可用 Set 方便实现。_.unionBy_.unionWith 是增强版。

// _.union([arrays]) - 创建一个按顺序排列的唯一值的数组。所有给定数组的元素值使用SameValueZero做等值比较。
// _.unionBy([arrays], [iteratee=_.identity]) - 这个方法类似_.union ,除了它接受一个 iteratee (迭代函数),调用每一个数组(array)的每个元素以产生唯一性计算的标准
// _.unionWith([arrays], [comparator]) - 这个方法类似_.union, 除了它接受一个 comparator 调用比较arrays数组的每一个元素。例如比较对象
{
r = _.union([1, 3, 5, 7, 3], [6, 4, 3]);
// => [1, 3, 5, 7, 6, 4]
l(r) // 两个数组也可以用 Set 实现
r = [...new Set([...[1, 3, 5, 7, 3], ...[6, 4, 3]])]
// or r = Array.from(new Set([...[1, 3, 5, 7], ...[6, 4, 3]]))
// => [1, 3, 5, 7, 6, 4]
l(r) // 比较处理后的值
r = _.unionBy([2.1], [1.2, 2.3], Math.floor)
// => [2.1, 1.2]
l(r) // 比较对象。对象的唯一性
const objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
const others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; r = _.unionWith(objects, others, _.isEqual);
// => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
l(r)
}

_.uniq 系列

_.uniq - 唯一(用于去重)。_.uniq 可用 Set 方便实现。_.uniqBy _.uniqWith 是增强版。

// _.uniq(array) - 创建一个去重后的array数组副本。
// _.uniqBy(array, [iteratee=_.identity]) - 这个方法类似_.uniq ,除了它接受一个 iteratee (迭代函数),调用每一个数组(array)的每个元素以产生唯一性计算的标准
// _.uniqWith(array, [comparator]) - 这个方法类似_.uniq, 除了它接受一个 comparator 调用比较arrays数组的每一个元素。例如比较对象
{
r = _.uniq([2, 1, 2]);
// => [2, 1]
l(r) r = [...new Set([2, 1, 2])]
// => [2, 1]
l(r) // 比较处理后的值
r = _.uniqBy([2.1, 1.2, 2.3], Math.floor);
// => [2.1, 1.2]
l(r) // 比较对象
r = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }]; r = _.uniqWith(r, _.isEqual);
// => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
l(r)
}

_.zip 系列

_.zip - 压缩。_.zipWith_.zipObject_.zipObjectDeep都是增强版

// _.zip([arrays]) - 创建一个分组元素的数组,数组的第一个元素包含所有给定数组的第一个元素,数组的第二个元素包含所有给定数组的第二个元素,以此类推。
// _.zipWith([arrays], [iteratee=_.identity]) - 这个方法类似于_.zip,不同之处在于它接受一个 iteratee(迭代函数),来指定分组的值应该如何被组合。
// _.zipObject([props=[]], [values=[]]) - 这个方法类似_.fromPairs,除了它接受2个数组,第一个数组中的值作为属性标识符(属性名),第二个数组中的值作为相应的属性值。
// _.zipObjectDeep([props=[]], [values=[]])- 这个方法类似_.zipObject,除了它支持属性路径。
{
r = _.zip([1, 2], [10, 20], [100, 200])
// => [[1, 10, 100], [2, 20, 200]]
l(r) // 自己实现一个弱版本
const zip = (...arrs) => {
const result = []
arrs[0].forEach((v, index) => {
const tmp = []
arrs.forEach(item => tmp.push(item[index]))
result.push(tmp)
})
return result
} r = zip([1, 2], [10, 20], [100, 200])
// => [[1, 10, 100], [2, 20, 200]]
l(r) r = _.zipWith([1, 2], [10, 20], [100, 200], function (a, b, c) {
return a + b + c;
});
// => [111, 222]
l(r) // 组合成对象
r = _.zipObject(['a', 'b'], [1, 2]);
// => { 'a': 1, 'b': 2 }
l(r) r = _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2])
// => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } }
l(r)
}

_.unzip 系列

_.unzip - 解压。似于_.zip。_.unzipWith 是增强版。

// _.unzip(array) - 这个方法类似于_.zip,除了它接收分组元素的数组,并且创建一个数组,分组元素到打包前的结构。(:返回数组的第一个元素包含所有的输入数组的第一元素,第一个元素包含了所有的输入数组的第二元素,依此类推。)
// _.unzipWith(array, [iteratee=_.identity]) - 此方法类似于_.unzip,除了它接受一个iteratee指定重组值应该如何被组合。增强版
{
r = _.unzip([1, 2], [10, 20], [100, 200])
// => []
l(r)
// 用数组包裹后,就和 _.zip 效果相同
r = _.unzip([[1, 2], [10, 20], [100, 200]])
// => [[1, 10, 100], [2, 20, 200]]
l(r) r = _.unzipWith([[1, 10, 100], [2, 20, 200]], _.add);
// => [3, 30, 300]
l(r)
}

_.without

_.without - 缺乏。可用 array.filter 替代

// _.without(array, [values]) - 创建一个剔除所有给定值的新数组。
{
r = _.without([2, 1, 2, 3], 1, 2);
// => [3]
l(r) r = [2, 1, 2, 3].filter(item => ![1, 2].includes(item))
// => [3]
l(r)
}

_.xor 系列

_.xor - X集(只存在于某个数组中的值)。_.xorBy_.xorWith 是增强版

// _.xor([arrays]) - 创建一个给定数组唯一值的数组,使用symmetric difference做等值比较。返回值的顺序取决于他们数组的出现顺序。每个元素的差集,即只存在于某个数组中的值,其他数组没有改值。
// _.xorBy([arrays], [iteratee=_.identity]) - 这个方法类似_.xor ,除了它接受 iteratee(迭代器),这个迭代器 调用每一个 arrays(数组)的每一个值,以生成比较的新值。增强版
// _.xorWith([arrays], [comparator]) - 该方法是像_.xor,除了它接受一个 comparator ,以调用比较数组的元素。增强版
{
r = _.xor([1, 2], [3, 2], [4, 2], [5])
// => [1, 3, 4, 5]
l(r)
r = _.xor([1, 2], [3, 2], [4, 2, 5], [5])
// => [1, 3, 4]
l(r) // 转换后的值比较
r = _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor);
// => [1.2, 3.4]
l(r) // 对象比较
const objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
const others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
r = _.xorWith(objects, others, _.isEqual);
// => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
l(r)
}

鸡肋

_.concat

_.concat - 连接数组。与 array.concat 效果相同,也可用 es6+ 语法 ... 实现

// _.concat(array, [values]) - 创建一个新数组,将array与任何数组 或 值连接在一起。
//
{
const array = [1];
r = _.concat(array, 2, [3], [[4]]); console.log(r);
// => [1, 2, 3, [4]] // 与原生数组的 concat 效果相同
r = array.concat(2, [3], [[4]])
// => [1, 2, 3, [4]]
l(r) r = [...array, 2, ...[3], ...[[4]]]
// [1, 2, 3, [4]]
l(r)
}
_.fill

_.fill - 填充。可用 array.fill 替代

// _.fill(array, value, [start=0], [end=array.length]) - 使用 value 值来填充(替换) array,从start位置开始, 到end位置结束(但不包含end位置)。
{ let array = [1, 2, 3];
r = [...array]
_.fill(r, 'a');
l(r)
// => ['a', 'a', 'a'] // array.fill 重写上一个示例
// fill() 方法用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引。
r = [...array]
r.fill('b')
l(r)
// => ['b', 'b', 'b'] r = [4, 6, 8, 10]
_.fill(r, '*', 1, 3)
l(r)
// => [4, '*', '*', 10] // array.fill 重写上一个示例
r = [4, 6, 8, 10]
r.fill('*', 1, 3)
l(r)
// => [4, '*', '*', 10]
}
_.findIndex

_.findIndex - 可用 Array.prototype.findIndex 替代

// _.findIndex(array, [predicate=_.identity], [fromIndex=0]) - 该方法类似_.find,区别是该方法返回第一个通过 predicate 判断为真值的元素的索引值(index),而不是元素本身。
// _.findLastIndex(array, [predicate=_.identity], [fromIndex=array.length-1])
{
let users = [
{ 'user': 'fred', 'active': false },
{ 'user': 'fred', 'active': true },
{ 'user': 'pebbles', 'active': true }
]; r = _.findIndex(users, function (o) { return o.user == 'fred' && o.active === false });
// => 0
l(r) // array.findIndex 重写上一个示例
// findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回 -1。
r = users.findIndex(o => o.user == 'fred' && o.active === false)
// => 0
l(r) // The `_.matches` iteratee shorthand.
r = _.findIndex(users, { 'user': 'fred', 'active': true });
// => 1
l(r)
}
_.head

_.head - 可用 arr[index] 或 att.at(index) 替代

// _.head(array) - 获取数组 array 的第一个元素。可用 arr[index] 或 att.at(index) 替代。
{
const arr = [2, 3, 4]
r = _.head(arr)
// => 2
l(r) // 需要 chrome 92+
// r = arr.at(0)
// => 2
// l(r)
}
_.flatten

_.flatten - 变平。array.flat 能非常方便的替代这3个api。

// _.flatten(array) - 减少一级array嵌套深度。
// _.flattenDeep(array) - 将array递归为一维数组。
// _.flattenDepth(array, [depth=1]) - 根据 depth 递归减少 array 的嵌套层级
{
let arr = [1, [2, [3, [4]], 5]]
r = _.flatten(arr);
// => [1, 2, [3, [4]], 5]
l(r) // array.flat 重写上一个示例
r = arr.flat()
// => [1, 2, [3, [4]], 5]
l(r) r = _.flattenDeep(arr)
// => [1, 2, 3, 4, 5]
l(r) // 用 array.flat 重写上一个示例
r = arr.flat(Infinity)
// => [1, 2, 3, 4, 5]
l(r)
}
_.remove

_.remove - 删除。可用 array.filter 替代。

// _.remove(array, [predicate=_.identity]) - 移除数组中predicate(断言)返回为真值的所有元素,并返回移除元素组成的数组
{
let array = [1, 2, 3, 4];
r = _.remove(array, function (n) {
return n % 2 == 0;
}); // => [2, 4]
l(r) // 用 array.filter 替代
r = [1, 2, 3, 4]
r = r.filter(item => item % 2 === 0)
// => [2, 4]
l(r)
}
_.tail

_.tail - 尾部。可用 array.slice 替代

// _.tail(array) - 获取除了array数组第一个元素以外的全部元素。
{
r = _.tail([1, 2, 3]);
// => [2, 3]
l(r) r = [1, 2, 3].slice(1)
// => [2, 3]
l(r)
}
其他
  • _.initial(array) - 获取数组array中除了最后一个元素之外的所有元素。名字不好记。可用 [1, 2, 3].slice(0, -1) 替代 或 let [, ...r] = [1,2,3].reverse(); r.reverse()

  • _.join(array, [separator=',']) - 可用 Array.prototype.join 替代

  • _.last(array) - 获取array中的最后一个元素。 可用 array[array.length - 1] 替代

  • _.lastIndexOf(array, value, [fromIndex=array.length-1]) - 可用 Array.prototype.lastIndexOf 替代

  • _.nth(array, [n=0]) - 获取array数组的第n个元素。直接用数组索引获取 或 Array.prototype.at 替代

  • _.reverse(array) - 逆序。可用 array.reverse 替代。

  • _.slice(array, [start=0], [end=array.length]) - slice。可用 array.slice 替代

  • _.indexOf - 可用 Array.prototype.indexOf 替代

陪你去看 Lodash.js 起步的更多相关文章

  1. 从源码的角度看 React JS 中批量更新 State 的策略(下)

    这篇文章我们继续从源码的角度学习 React JS 中的批量更新 State 的策略,供我们继续深入学习研究 React 之用. 前置文章列表 深入理解 React JS 中的 setState 从源 ...

  2. 从源码的角度看 React JS 中批量更新 State 的策略(上)

    在之前的文章「深入理解 React JS 中的 setState」与 「从源码的角度再看 React JS 中的 setState」 中,我们分别看到了 React JS 中 setState 的异步 ...

  3. h5 plus/h5+规范使用,模块索引,教你如何去看h5+的手册

    最近看了下h5+规范的官网,开始觉得晦涩难懂,确实很乱,不过这也是基于我不理解的情况,终于艰难读完了,现在来分享下心得吧,基本看完文章,按我的方法,应该可以直接上手项目. 我准备的工具 hbuilde ...

  4. 一篇文章看懂JS闭包,都要2020年了,你怎么能还不懂闭包?

     壹 ❀ 引 我觉得每一位JavaScript工作者都无法避免与闭包打交道,就算在实际开发中不使用但面试中被问及也是常态了.就我而言对于闭包的理解仅止步于一些概念,看到相关代码我知道这是个闭包,但闭包 ...

  5. 擦亮自己的眼睛去看SQLServer之简单Insert(转)

    摘要:本来是打算先写SQLServer历史的,不过感觉写那部分内容比较难还需要多查些资料.于是调整了下顺序写下简单的Insert语句. 不过感觉写那部分内容比较难还需要多查些资料.于是调整了下顺序写下 ...

  6. 我追一个处女座的女孩快两个月了,我之前聊得很好,她说过有空call我去看电影,过了一个月她就不理我了,我喜欢她, 我是程序员,百度发不了那么多字。

    她刚刚进公司的时候,公司组织去打球,我叫她一起去她也去了,我和她聊了很多,聊得很自然,很开心,如我是哪个学习毕业的 我出来工作多久了等,她也聊了 她自己好多,她现在在读大学,只有周日上一天课那种. 我 ...

  7. lodash (js实用工具库)

    是什么? 它提供了一整套函数式编程的实用功能, 并且支持模块化, 比underscore更优秀. 文档? http://lodashjs.com/docs/ 引用? <script src=&q ...

  8. Lodash.js常用拷贝

    lodash.js 降低 array.number.objects.string 等等的使用难度从而让 JavaScript 变得更简单.非常适用于:遍历 array.object 和 string: ...

  9. Codevs 1570 去看电影

    1570 去看电影  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解  查看运行结果     题目描述 Description 农夫约翰带着他的一些奶牛去看 ...

随机推荐

  1. 【JavaWeb】学习路径1-背景

    JavaWeb系列也是一个非常庞大的系列,主要分为五个部分讲解: HTML JSP和Servlet CSS的讲解 JavaScrip的讲解 jQuery框架的讲解 学习完上述内容后,就能够基本了解一个 ...

  2. 【java】学习路线6-静态方法、私有化方法、父类子类

    import java.util.Arrays; /* 我们可以自己创建方法(静态) 私有化方法,阻止他人实例化该方法 静态代码块只执行一次,只在加载这个所在类的时候执行 父类 - 子类 子类继承自父 ...

  3. 「题解报告」P3354

    P3354 题解 题目传送门 一道很恶心的树形dp 但是我喜欢 题目大意: 一片海旁边有一条树状的河,入海口有一个大伐木场,每条河的分叉处都有村庄.建了伐木场的村庄可以直接处理木料,否则要往下游的伐木 ...

  4. k8s中ingress,service,depoyment,pod如何关联

    k8s中pod通过label标签名称来识别关联,它们的label  name一定是一样的.ingress,service,depoyment通过selector 中app:name来关联 1.查询发布 ...

  5. 大家都能看得懂的源码 - 那些关于DOM的常见Hook封装(二)

    本文是深入浅出 ahooks 源码系列文章的第十五篇,该系列已整理成文档-地址.觉得还不错,给个 star 支持一下哈,Thanks. 本篇接着针对关于 DOM 的各个 Hook 封装进行解读. us ...

  6. 踩坑 Windows 服务来宿主 .NET 程序

    本文所指的 .NET 程序为 .NET6 的程序.因为 .NET 的版本更新很快,所以方式.方法也有变化,所以网上搜到的方法有些也过时了.以下是最近我实践下来的一点心得(坑). 上一篇说到 不安装运行 ...

  7. Job And Schedule (V8R6C3)

    KingbaseES 数据库提供了 kdb_schedule 扩展,使得用户能通过类似oracle job 的方式进行job调用.kdb_schedule 提供了三个Schema :dbms_job ...

  8. systemctl_用法总结

    查看开机启动项 //查询开机启动项 systemctl list-unit-files // 输出 UNIT FILE 对应服务名:STATE 是状态:enable 是开机启动,disable是开机不 ...

  9. 【ACG】博主在专栏更新内容后,及时通知关注他的用户去阅读

    ​ 业务场景 当用户打开应用时,系统发送Push消息给用户,向用户推荐博主信息.用户关注博主后,将保存用户的订阅信息,当关注的博主更新内容时,向订阅的用户发送短信,提醒用户及时查看最新内容.从而持续增 ...

  10. G&GH02 储存库创建/同步

    注意事项与声明 平台: Windows 10 作者: JamesNULLiu 邮箱: jamesnulliu@outlook.com 博客: https://www.cnblogs.com/james ...