1 简介
Lodash是一款优秀的 JavaScript 工具库,里面包含了大量的工具函数。在 2015 年就成为被依赖最多的 JavaScript 库,写这篇文档是最新版是 4.17.4,适用于常见浏览器以及 Node.js 等。
这里给出其英文文档和中文文档的链接。其中中文文档的版本较低,但是区别不大,可以参考帮助理解。
2 常见用法
在这部分我们介绍一些 Lodash 的常见的优雅的用法。主要是引起大家的学习兴趣,有更多优雅用法等待大家去发现。
_.get获取一个嵌套很深的字段
1 | //config 初始化为 null,需要从服务器端获取权限数据 |
对应地,可以通过_.set({}, 'a.b.c', 1)创建一个多级嵌套的对象。
_.map获取数组中每个对象的特定字段,并形成一个新的数组
1 | //使用所有用户的 idCard 字段创建出一个数组 |
_.pick取出对象的部分字段形成一个新对象
1 | //在修改密码表单里,用户输入了如下字段并被封装到一个对象中 |
对应地,还有_.omit方法表示删除部分字段形成一个新对象。
_.random获取一个随机值
1 | //获取[90, 100)之内的一个随机值 |
类似地,_.sample(['a', 'b', 'c'])可以从数组中随机取出一个项目。
_.clamp将一个数字修改成区间中的一个值
1 | //使用原生JS |
_.once确保一个函数只会执行一次
1 | //使用原生JS |
_.chain链式操作
链接调用让代码更加整洁;避免了中间变量,避免了错误引用,让代码质量更有保证;_.chain还提供了延迟计算特性,在显式或隐式调用value()方法之前是不进行任何计算的,通过合并大大降低迭代次数。
下面是lodash的官方文档中的一个例子。
1 | var users = [{ user: 'barney', age: 36 }, { user: 'fred', age: 40 }, { user: 'pebbles', age: 1 }]; |
3 模块
Lodash 的工具函数很多,可以分为以下几类:数组(Array),集合(Collection),函数(Function),Lang(Lang),数学(Math),数字(Number),对象(Object),字符串(String),未分类工具函数(Util)。下面将会按类别介绍常见工具函数。
4 数组
获取子数组
| 函数名 | 简介 |
|---|---|
| slice | 获取元素第 m-n(不包含)个元素 |
| tail | 获取出第一个元素之外的其他元素 |
| initial | 获取出最后一个元素之外的其他元素 |
| take | 从左侧开始获取任意数量的元素 |
| takeRight | 从右侧开始获取任意数量的元素 |
| takeWhile | 从左侧开始获取任意数量的元素,直到断言返回假值 |
| takeRightWhile | 从右侧开始获取任意数量的元素,直到断言返回假值 |
| drop | 丢掉前面几个元素,得到剩余元素 |
| dropWhile | 丢掉前面几个元素知道迭代器返回假值,得到剩余元素 |
| dropRight | 丢掉后面几个元素,得到剩余元素 |
| dropRightWhile | 丢掉后面几个元素知道迭代器返回假值,得到剩余元素 |
数组常见操作
| 操作 | 不修改原数组 | 修改原数组 |
|---|---|---|
| 移除 | without | pull |
| 相减 | difference | pullAll |
| 相减 | differenceBy | pullAllBy |
| 相减 | differenceWith | pullAllWith |
| 反转 | reverse | |
| 裁剪 | at | pullAt |
| 过滤 | filter | remove |
数组常见操作变种函数 by, with
有些函数还可以稍微变化一下,接受不同的参数,提供更多灵活性。
| 作用 | 函数名 | by | with |
|---|---|---|---|
| 相减 | difference | differenceBy | differenceWith |
| 交集 | intersection | intersectionBy | intersectionWith |
| 并集 | union | unionBy | unionWith |
| 异或 | xor | xorBy | xorWith |
| 相减 | pullAll | pullAllBy | pullAllWith,跟difference不同的是,pullAll修改原数组 |
| 去重 | uniq | uniqBy | uniqWith |
| 去重 | sortedUniq | sortedUniqBy |
获取数组某个位置上的元素
| 函数名 | 主要参数-返回值 | 简介 |
|---|---|---|
| head | 数组=>元素 | 返回数组的第一个元素,和first相同 |
| last | 数组=>元素 | 返回数组的最后一个元素,和head相反 |
| nth | 数组=>元素 | 返回数组中某个位置上的元素 |
检测元素在数组中的索引
| 函数名 | 简介 |
|---|---|
| indexOf | 获取元素在数组中的索引 |
| sortedIndexOf | 和indexOf功能一致,只是通过二分搜索方法 |
| lastIndexOf | 获取元素在数组中的索引,最后一次出现 |
| sortedLastIndexOf | 和lastIndexOf功能一致,只是通过二分搜索方法 |
| findIndex | 寻找元素位置 |
| findLastIndex | 寻找元素位置,从后往前 |
检测元素在插在有序数组的什么位置
| 函数名 | 简介 |
|---|---|
| sortedIndex | 通过二分搜索判断元素应该插在数组的哪个位置 |
| sortedIndexBy | 同上,可以额外提供一个迭代器函数 |
| sortedLastIndex | 和sortedIndex类似,但是从右边开始 |
| sortedLastIndexBy | 同上,可以额外提供一个迭代器函数 |
将数组拍平
| 函数名 | 主要参数-返回值 | 简介 |
|---|---|---|
| flatten | 高维数组=>低维数组 | 将数组拍平 |
| flattenDeep | 高维数组=>数组 | 将数组拍平 |
| flattenDepth | 高维数组=>低维数组 | 将数组拍平 |
Zip
| 函数名 | 主要参数-返回值 | 简介 |
|---|---|---|
| zip | 多个数组=>二维数组 | 可以理解为二维数组的行列互换 |
| zipWith | 多个数组=>数组 | 同上,但是可以自由处理行列互换后的数组中的每个数组元素 |
| zipObject | 两个数组=>对象 | 把 keys 和 values 数组组成一个新对象 |
| zipObjectDeep | 两个数组=>对象 | 同上,递归地处理属性名 |
未分类函数
| 函数名 | 主要参数-返回值 | 简介 |
|---|---|---|
| chunk | 数组=>二维数组 | 分段形成二维数组 |
| compact | 数组=>数组 | 移除假值 |
| concat | 多个数组=>数组 | 连接多个数组形成一个数组 |
| fill | 数组=>数组 | 填充数组 |
| fromPairs | 二维数组=>对象 | 将键值数组变成对象。和toPairs相反 |
| join | 数组=>字符串 | 拼接数组元素成一个字符串 |
5 集合
为什么区分集合函数和数组函数?
集合函数不单单适用于数组,还适用于字符串,对象,类数组对象(比如 Arguments,NodeList 等)。字符串是字符的集合,对象是属性值的集合。类数组对象是通过“鸭子类型”工作的,所以如果你传入一个拥有length字段并且值为数字的对象,这个对象会被当做一个数组处理。具体请参考Underscore.js文档。
范例:
1 | function printKeyVal(val, key) { |
下面将分类介绍集合相关函数。
遍历
| 函数名 | 简介 |
|---|---|
| each | 同forEach |
| eachRight | 同forEachRight |
排序
| 函数名 | 简介 |
|---|---|
| sortBy | 排序 |
| orderBy | 同sortBy,还可以指定正序倒序 |
| shuffle | 返回一个打乱顺序的新数组 |
过滤
| 函数名 | 简介 |
|---|---|
| filter | 创建一个新数组,包含了所有让断言为真的元素 |
| reject | 创建一个新数组,包含了所有让断言为假的元素 |
| partition | 根据断言真假将一个集合分成两个集合 |
Map 之后再 flatten
| 函数名 | 简介 |
|---|---|
| flatMap | map之后再flatten |
| flatMapDeep | map之后再flattenDeep |
| flatMapDepth | map之后再flattenDepth |
寻找元素
| 函数名 | 简介 |
|---|---|
| find | 找到第一个让断言为真的元素 |
| findLast | 同上,逆序 |
随机取值
| 函数名 | 简介 |
|---|---|
| sample | 从集合中随机选出一个元素 |
| sampleSize | 从集合中随机选出 n 个元素 |
迭代
| 函数名 | 简介 |
|---|---|
| reduce | |
| reduceRight | - |
分组计数
| 函数名 | 简介 |
|---|---|
| countBy | 返回一个对象,属性名是迭代器的返回值,属性值该返回值出现的次数 |
| groupBy | 返回一个对象,属性名是迭代器的返回值,属性值是一个包含了相应元素的数组 |
未分类
| 函数名 | 简介 |
|---|---|
| keyBy | 返回一个对象,属性名是迭代器的返回值,属性值是元素本身 |
| some | 对于集合中的每个元素,是否至少其一返回真值 |
| every | 对于集合中的每个元素,是否都返回真值 |
| includes | 判断元素是不是在数组中,判断某个值是不是某个对象的属性值,判断一个字符串是不是包含在另一个字符串中 |
| map | 对集合的数组 |
| invokeMap | - |
6 对象
仅需要部分字段
| 函数名 | 简介 |
|---|---|
| omit | 通过忽略某些字段创建一个新对象 |
| omitBy | |
| pick | 通过指定某些字段创建一个新对象 |
| pickBy | - |
合并对象
| 函数名 | 简介 |
|---|---|
| assign | 合并对象 |
| assignWith | 有条件地合并对象 |
| extend | 合并对象,包括原型链上的属性 |
| extendWith | 有条件地合并对象,包括原型链上的属性 |
| assignIn | 别名extend |
| assignInWith | 别名extendWith |
| defaults | 合并对象,将后面参数的属性付给第一个参数,如果第一个参数没有相应属性的话 |
| defaultsDeep | 递归地合并对象,将后面参数的属性付给第一个参数,如果第一个参数没有相应属性的话 |
| merge | 递归地合并对象,将后面参数的属性付给第一个参数 |
| mergeWith | 同merge,额外接受一个 customizer 参数 |
键值列表
| 函数名 | 简介 |
|---|---|
| keys | 创建一个数组,包含对象中所有的属性 |
| keysIn | 创建一个数组,包含对象中所有的属性(包含原型链上的) |
| functions | 创建一个数组,包含对象中所有值为函数的属性 |
| functionsIn | 创建一个数组,包含对象中所有值为函数的属性(包含原型链上的) |
| values | 创建一个数组,包含对象中所有的属性值 |
| valuesIn | 创建一个数组,包含对象中所有的属性值(包含原型链上的) |
赋值取值
| 函数名 | 简介 |
|---|---|
| at | 获取对象的一组属性路径的值,肯定不会报错 |
| get | 获取对象的某个属性路径的值,肯定不会报错 |
| result | 同get,但是如果属性值是函数的话,自动执行该函数 |
| set | 设置对象的某个属性路径的值 |
| setWith | 设置对象的某个属性路径的值,遇到不存在的中间对象,使用数组呢?还是使用对象呢?等等 |
| update | 同set,只是接受一个函数作为参数 |
| updateWith | 同setWith,只是接受一个函数作为参数 |
| unset | 删除对象的某个属性路径 |
| invoke | 调用对象中某个属性路径上的函数,肯定不会报错 |
键值数组
| 函数名 | 简介 |
|---|---|
| entries | {‘a’:1}=>[[‘a’,1]]。别名toPairs |
| entriesIn | 同上,但是包含原型链上的属性。别名toPairsIn |
键值变换
| 函数名 | 简介 |
|---|---|
| mapKeys | 对对象中所有属性名做某种处理之后形成一个新对象 |
| mapValues | 对对象中所有属性值做某种处理之后形成一个新对象 |
| invert | 将对象中的属性名和属性值互换转成一个新对象 |
| invertBy | 同invert,但是转换以后的属性值是原属性值组成的数组 |
键值遍历
| 函数名 | 简介 |
|---|---|
| forIn | 遍历对象上的所有属性,包含原型链上的。 |
| forInRight | 遍历对象上的所有属性,包含原型链上的。 |
| forOwn | 遍历对象上的所有属性,不包含原型链上的。 |
| forOwnRight | 遍历对象上的所有属性,不包含原型链上的。 |
寻找属性
| 函数名 | 简介 |
|---|---|
| findKey | 同find类似,但是匹配的是对象的属性值,返回的是对象的属性名 |
| findLastKey | 同findKey类似,但是匹配的是对象的属性值,返回的是对象的属性名 |
判断属性是否存在
| 函数名 | 简介 |
|---|---|
| has | 判断对象上是否拥有某个属性,不包含原型链上的 |
| hasIn | 判断对象上是否拥有某个属性,包含原型链上的 |
转换对象或数组
| 函数名 | 简介 |
|---|---|
| transform | 同reduce,但是其迭代器函数返回的是布尔值,如果返回 false,则停止迭代 |
创建新对象
| 函数名 | 简介 |
|---|---|
| create | 创建一个对象,并指定其原型和属性 |
7. 函数
修改参数
| 函数名 | 简介 |
|---|---|
| ary | 创建一个包裹函数,只将前 n 个参数传递给原函数。 |
| unary | 创建一个包裹函数,只将第一个参数传递给原函数。 |
| flip | 创建一个包裹函数,将参数逆序之后传递给原函数。 |
| rearg | 创建一个包裹函数,调整参数顺序之后在传递给原函数 |
| rest | 创建一个包裹函数,将参数合成数组之后传递给原函数 |
| spread | 创建一个包裹函数,将数组参数展开之后传给原函数,跟rest相反 |
| overArgs | 创建一个包裹函数,将参数做处理之后再传递给原函数。 |
修改结果
| 函数名 | 简介 |
|---|---|
| negate | 创建一个包裹函数,返回原函数结果的非。 |
缓存结果
| 函数名 | 简介 |
|---|---|
| memoize | 创建一个包裹函数,会缓存计算结果 |
降频调用
| 函数名 | 简介 |
|---|---|
| debounce | |
| throttle |
延迟调用
| 函数名 | 简介 |
|---|---|
| defer | 类似setTimeout(fn,0),可以指定参数 |
| delay | 类似setTimeout(fn,x),可以指定参数 |
延迟调用
| 函数名 | 简介 |
|---|---|
| once | 创建一个包裹函数,确保原函数只被执行一次。 |
| before | 创建一个包裹函数,确保原函数只被执行 n 次。 |
| after | 创建一个包裹函数,调用包裹函数时只有 n 次之后才会调用目标函数 |
固定参数
| 函数名 | 简介 |
|---|---|
| wrap | 创建一个包裹函数,固定原函数的第一个参数 |
| partial | 创建一个包裹函数,固定原函数若干个参数 |
| partialRight | 创建一个包裹函数,固定原函数若干个参数 |
| bind | 创建一个包裹函数,固定原函数若干个参数,并指定 this 对象 |
| bindKey | 和bind功能类似,但是能够处理尚未创建或被重写的函数,有点事件代理的感觉。 |
| curry | 创建一个包裹函数,可以传入任意数量的参数,如果参数不完整,则返回一个接受余下参数的新函数,否则,调用原函数获得计算结果。 |
| curryRight | 同上,逆序 |
8. 字符串
书写格式
| 函数名 | 简介 |
|---|---|
| startCase | 每个单词首字母大写,多用于标题 |
| camelCase | 小驼峰 |
| kebabCase | 小写连字符 |
| snakeCase | 小写下划线 |
| upperCase | 大写加空格 |
| lowerCase | 小写加空格 |
大写小写
| 函数名 | 简介 |
|---|---|
| capitalize | 首字母大写,其余小写 |
| upperFirst | 首字母大写,其余不变 |
| lowerFirst | 首字母小写,其余不变 |
| toUpper | 大写 |
| toLower | 小写 |
打头结尾
| 函数名 | 简介 |
|---|---|
| endsWith | 是不是以特定字符串结尾 |
| startsWith | 是不是以特定字符串打头 |
转义
| 函数名 | 简介 |
|---|---|
| escape | 转义 &<>”‘,与unescape相反 |
| escapeRegExp | 转义正则表达式中的特殊字符:^\$.*+?()[]{}\ |
补全抹掉
| 函数名 | 简介 |
|---|---|
| pad | 使用某个字符串将特定字符串扩充至指定长度,类似地还有padStart,padEnd |
| trim | 去除字符串两边的特殊字符(默认为空格),类似地还有trimStart,trimEnd |
未分类
| 函数名 | 简介 |
|---|---|
| parseInt | 转成整型 |
| repeat | 将某个字符串重复 n 遍 |
| replace | 替换字符串 |
| split | 拆分字符串 |
| template | 简单模板引擎 |
| truncate | 截断字符串 |
| words | 将字符串拆分成单词,可以指定拆分模式 |
| deburr | 基本拉丁字母 |
9. 数字
| 函数名 | 主要参数-返回值 | 简介 |
|---|---|---|
| clamp | 数字=>数字 | 将数字限定在一个范围内 |
| inRange | 数字=>布尔 | 判断数字是否在某个区间里 |
| random | 区间=>数字 | 随机获取一个值,可以通过第三个参数指定是不是返回小数 |
10. 数学
加减乘除
| 函数名 | 主要参数-返回值 | 简介 |
|---|---|---|
| add | 两个数字 => 数字 | 返回两个数字的和 |
| subtract | 两个数字 => 数字 | 返回两个数字的差 |
| multiply | 两个数字 => 数字 | 返回两个数字的积 |
| divide | 两个数字 => 数字 | 返回两个数字的商 |
和,最大值,最小值,平均值
| 函数名 | 主要参数-返回值 | 简介 |
|---|---|---|
| sum | 数组 => 数字 | 返回数组中的各数字之和 |
| max | 数组 => 数字 | 返回数组中的最大值 |
| min | 数组 => 数字 | 返回数组中的最小值 |
| mean | 数组 => 数字 | 返回数组中的平均值 |
数字精度
| 函数名 | 主要参数-返回值 | 简介 |
|---|---|---|
| ceil | 数字 => 数字 | 向上取整,可以指定精度 |
| floor | 数字 => 数字 | 向下取整,可以指定精度 |
| round | 数字 => 数字 | 四舍五入取整,可以指定精度 |
11. 语言
数值比较
| 函数名 | 简介 |
|---|---|
| eq | 等价于=== |
| isEqual | 深度比较对象是否相等 |
| isEqualWith | 深度比较对象是否相等,可以定义相等比较函数 |
| gt | 大于 |
| lt | 小于 |
| gte | 大于等于 |
| lte | 小于等于 |
类型判断
| 函数名 | 简介 |
|---|---|
| isArguments | |
| isArray | |
| isArrayBuffer | |
| isArrayLike | |
| isArrayLikeObject | |
| isBoolean | |
| isBuffer | |
| isDate | |
| isElement | |
| isEmpty | 判断是否有可遍历的属性 |
| isError | 错误 |
| isFinite | 是否是有限的数字,基于 Number.isFinite |
| isFunction | |
| isInteger | |
| isLength | |
| isMap | |
| isMatch | |
| isMatchWith | |
| isNaN | |
| isNative | 原生函数 |
| isNil | 等价于 _.isNull(val) || _.isUndefined(val) |
| isNull | |
| isNumber | |
| isObject | |
| isObjectLike | |
| isPlainObject | |
| isRegExp | |
| isSafeInteger | |
| isSet | isSet |
| isString | |
| isSymbol | |
| isTypedArray | |
| isUndefined | |
| isWeakMap | |
| isWeakSet |
类型转换
| 函数名 | 简介 |
|---|---|
| castArray | 强制转给数组 |
| toArray | 转成数组,对象调用 Object.values,字符串转成字符数组 |
| toFinite | |
| toInteger | |
| toLength | |
| toNumber | |
| toPlainObject | |
| toSafeInteger | |
| toString | 转成字符串, |
复制对象
| 函数名 | 简介 |
|---|---|
| clone | |
| cloneDeep | |
| cloneDeepWith | |
| cloneWith |
检测对象
| 函数名 | 简介 |
|---|---|
| conformsTo | 判断一个对象的字段是否满足一些条件 |
12. 工具
总是返回某个参数的函数
| 函数名 | 简介 |
|---|---|
| constant | 创建一个包裹函数,总是返回第一个参数 |
| nthArg | 创建一个包裹函数,总是返回第 n 个参数 |
总是返回某个特定值的函数
| 函数名 | 简介 |
|---|---|
| noop | 总是返回undefined的函数 |
| stubArray | 总是返回空数组的函数 |
| stubObject | 总是返回空对象的函数 |
| stubString | 总是返回空字符串的函数 |
| stubTrue | 总是返回true的函数 |
| stubFalse | 总是返回false的函数 |
| identity | 总是返回第一个参数 |
获取对象的属性值或者调用对象的函数
| 函数名 | 简介 |
|---|---|
| method | _.invoke(object, path, [args])预设path和args两个参数 |
| methodOf | _.invoke(object, path, [args])预设object和args两个参数 |
| property | _.get(object, path)预设path参数,不同的是缺少defaultValue`参数 |
| propertyOf | _.get(object, path)预设object参数,不同的是缺少defaultValue参数 |
判断对象是否满足某些条件
| 函数名 | 简介 |
|---|---|
| conforms | 创建一个包裹函数,判断一个对象的字段是否满足某个函数。conforms意思是遵守。 |
| matches | 创建一个包裹函数,判断一个对象的字段是否等于某个值,使用isEqual判断是否相等。跟isMatch类似 |
| matchesProperty | 创建一个包裹函数,判断一个对象特定字段是否等于某个值,使用isEqual判断是否相等。 |
把多个操作合成一个操作
| 函数名 | 简介 |
|---|---|
| flow | 把一组函数串起来形成一个新函数 |
| flowRight | 同上,倒序 |
批量进行多个操作
| 函数名 | 简介 |
|---|---|
| over | 创建一个新函数,并将参数传递给预先指定的一组函数,并返回其结果 |
| overEvery | 跟over类似,判断是不是所有函数都返回真值 |
| overSome | 跟over类似,判断是不是至少一个函数返回真值 |
等差数列
| 函数名 | 简介 |
|---|---|
| range | 生成等差数列,可以指定步长,步长可以是小数,也可以是负数 |
| rangeRight | 这个基本可以忽略,功能完成可以由range代替。 |
其他未分类
| 函数名 | 简介 |
|---|---|
| attempt | 使用 try-catch 包裹函数,如果出错返回错误对象 |
| bindAll | 将一个对象的多个函数中的 this 固定为该对象 |
| cond | 创建一个拥有复杂 if-else 的函数 |
| defaultTo | 如果第一个参数为 NaN,null,undefined,则返回第二个参数,否则返回第一个参数 |
| iteratee | 创建一个迭代函数 |
| noConflict | 如果_被占用,可以使用该方法 |
| runInContext | 创建一个lodash镜像对象,可以扩展修改该对象 |
| mixin | 给一个对象的原型添加属性或方法,一般配合runInContext扩展lodash。 |
| times | 执行函数 n 次,传入参数为 index |
| toPath | ‘a[0].b.c’=>[‘a’,’0’,’b’,’c’] |
| uniqueId | 生成唯一 ID,可以指定前缀 |
13. 链式
链式调用的好处
省略了中间变量,让代码更加简洁,更加安全。
链式调用可以优化成惰性求值(延迟计算),让代码更加高效。
_(value)
创建一个经过 lodash 包装过后的对象会启用隐式链,直到调用了不支持链接调用的函数或者主动调用value方法解除链式调用。
作用类似于chain
lodash 包装对象上的特殊函数
| 函数名 | 简介 |
|---|---|
| tap | 可以在链式调用中插入普通方法,直接修改中间结果,也可以仅仅是用于调试打印中间结果 |
| thru | 同tap,但是使用函数的返回值作为中间结果 |
| commit | 立即执行链式调用中尚未进行的操作 |
| next | 获得包装对象的下一个值 |
| plant | 复制一个链式调用,并传入初始值 |
| value | 结束链式调用,并计算结果。别名valueOf,toJSON |