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. Kingbase V8R6集群安装部署案例---脚本在线一键扩容

    案例说明: KingbaseES V8R6支持图形化方式在线扩容,但是在一些生产环境,在服务器不支持图形化界面的情况下 ,只能通过脚本命令行的方式执行集群的部署或在线扩容. Tips: Kingbas ...

  2. KingbaseES函数如何返回结果集

    函数返回值一般是某一类型值,如int,varchar,date等,返回结果集时就需要用到setof语法. 创建数据 create table class(id number primary key, ...

  3. KingbaseFlySync 版本升级

    关键字: KingbaseFlySync.Linux.x86_64.mips64el.aarch64.Java 拓扑图: 客户现场源端和目标端写在一个flysync.ini中,所以不单独把目标端拿出来 ...

  4. Redis变慢?深入浅出Redis性能诊断系列文章(三)

    (本文首发于"数据库架构师"公号,订阅"数据库架构师"公号,一起学习数据库技术,助力职业发展) 本篇为Redis性能问题诊断系列的第三篇,主要从Redis服务层 ...

  5. Andrej Karpathy | 详解神经网络和反向传播(基于 micrograd)

    只要你懂 Python,大概记得高中学过的求导知识,看完这个视频你还不理解反向传播和神经网络核心要点的话,那我就吃鞋:D Andrej Karpathy,前特斯拉 AI 高级总监.曾设计并担任斯坦福深 ...

  6. MySQL常用函数整理,建议收藏!

    常见函数 字符串函数 数字函数 日期函数 聚合函数 流程控制函数 一.字符串函数 concat(s1,s2...,sn) --将s1,s2...,sn连接成字符串,如果该函数中的任何参数为 null, ...

  7. Springboot配置文件参数使用docker-compose实现动态配置

    文章总结; Springboot配置文件中的一些参数可以写成变量的形式,具体变量的值可以从docker-compose.yml文件中设置来获取 在yml文件中,通过${Envirment_variab ...

  8. 使用KubeOperator安装k8s集群后,节点主机yaml文件路径

    [root@k8s-develop-master-1 kubernetes]# cd /etc/kubernetes [root@k8s-develop-master-1 kubernetes]# l ...

  9. Query String Query和Sumple Query String

  10. PVC-U排水管及管件