lodash 起步(数组)

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

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

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

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

环境准备

直接通过引用 bootstrap 免费的 cdn 的方式进行,只需两个文件:index.html 和 test-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. 【JDBC】学习路径1-JDBC背景知识

    学习完本系列JDBC课程后,你就可以愉快使用Java操作我们的MySQL数据库了. 各种数据分析都不在话下了. 第一章:废话 JDBC编程,就是写Java的时候,调用了数据库. Java Databa ...

  2. 【MySQL】DDL因Waiting for table metadata lock卡住

    在数据库空闲时间,对表做碎片整理: alter table my_abc engine=innodb; 发现会话被阻塞,显示状态是: Waiting for table metadata lock 手 ...

  3. KingbaseES R6 集群手工配置VIP案例

    经常有用户问,V8R6集群搭建时没有配置VIP,搭建完成后,如何添加VIP?以下向大家介绍下手动添加VIP 的过程. 一.操作系统环境 操作系统(UOS): root@uos01:~# cat /et ...

  4. (一)JPA的快速入门

    JPA简介 JPA是什么 JPA 是Java Persistence API的缩写,是一套由Java官方制定的ORM标准.当制定这套标准以后,市场上就出现很多JPA框架.如:OpenJPA(apach ...

  5. vue3 的 ref、isRef、toRef、toRefs、toRaw 详细介绍

    ref.isRef.toRef.toRefs.toRaw 看着一堆类似的东西,一个头两个大,今天整理一篇文章详细介绍它们的功能及区别. 1.ref ref 属性除了能够获取元素外,也可以使用 ref ...

  6. kubeadm init 命令执行流程

  7. 安装krew

    地址:https://krew.sigs.k8s.io/docs/user-guide/setup/install/ macOS/Linux Bash or ZSH shells 确保已安装git 2 ...

  8. Fluentd部署:错误排查

    介绍一下排查Fluentd运行时错误的几种方法. 查看日志 如果感觉Fluentd运行异常,请先查看日志.td-agent安装后,默认日志存放在/var/log/td-agent/td-agent.l ...

  9. TCP和UDP有啥区别?

    TCP全称: Transmission Control Protocol中文名: 传输控制协议解释: 是一种面向连接的.可靠的.基于字节流的传输层通信协议,由IETF的RFC 793定义.用途:TCP ...

  10. RabbitMQ原理和架构图解(附6大工作模式)

    为什么要使用RabbitMQ? 1.解耦 系统A在代码中直接调用系统B和系统C的代码,如果将来D系统接入,系统A还需要修改代码,过于麻烦. 2.异步 将消息写入消息队列,非必要的业务逻辑以异步的方式运 ...