Lodash 入门:从零开始
起源与目标
前端开发中,数据处理占了业务逻辑的 “半壁江山”,但原生 JavaScript API 在复杂场景下总显得 “力不从心”。而 Lodash 作为前端生态中最经典的工具库之一,提供了很多处理数组、对象、字符串等的便捷方法,旨在简化常见的数组、对象、字符串、函数以及其他数据结构的操作。Lodash 并非 “花里胡哨的工具集合”,而是基于前端开发痛点诞生的 “解决方案库”。它的核心价值,在于用更优雅的方式解决 “原生 API 搞不定或搞不好” 的问题,彻底告别 “数据处理焦虑”。
由于原生 Lodash 库为了保持广泛浏览器兼容性,默认使用 CommonJS 模块格式(适用于Node.js环境和老版浏览器),这可能导致在现代前端项目中引入整个库时,即使只使用其中少数几个函数,也需加载整个库的代码,造成不必要的网络传输和客户端资源消耗。lodash-es 应运而生,旨在为那些支持ES模块的项目提供一个更轻量、更易于优化的Lodash版本。Lodash-es 是流行 JavaScript 工具库 Lodash 的 ES 模块版本,提供了与 lodash 完全一致的 API,但采用原生 ES Module 格式导出,能大幅简化开发中的数据处理、数组/对象操作、函数防抖节流、深拷贝等场景的代码,提升开发效率和代码健壮性。是现代前端工程的首选工具库,配合 Vite、Webpack、Rollup 等打包工具可以实现完美的 Tree Shaking,大幅减少产物体积。
- 官网:lodash.com/docs
- 中文网:www.lodashjs.com/
快速集成
安装依赖
如果正在使用 Node.js 的包管理器 npm,打开终端或命令提示符,进入项目根目录,然后执行以下命令:
# 核心库(ES 模块版本)
npm install lodash-es
按需引入
完成安装后,就可以在项目中导入并使用 lodash-es 提供的工具函数。Lodash-es 支持按需导入,可以显著减少打包体积,是现代 JavaScript 项目中的首选工具库。
// 单函数引入(推荐)
import { debounce } from 'lodash-es';
import { cloneDeep, merge } from 'lodash-es';
import chunk from 'lodash-es/chunk';
// 也可以从单独文件导入(更利于 Tree-shaking)
import debounce from 'lodash-es/debounce';
import throttle from 'lodash-es/throttle';
核心高频功能
数组(Array)
lodash-es 提供了丰富的数组处理函数,涵盖分块、扁平化、去重、排序等常见场景。
| 函数 | 简要说明 | 示例 |
|---|---|---|
| uniq | 去重 | uniqBy([{id:1},{id:1},{id:2}], 'id') → [{id:1},{id:2}] |
| difference | 差集 | difference([1,2,3],[2,4]) → [1,3] |
| intersection | 交集 | intersection([1,2,3],[2,3,4]) → [2,3] |
| union | 并集 | union([1,2],[2,3]) → [1,2,3] |
| drop、dropRight | 去掉前/后 n 个元素 | drop([1,2,3], 1) → [2,3] |
| take、takeRight | 取前/后 n 个元素 | take([1,2,3], 2) → [1,2] |
| fill | 填充数组 | fill(Array(3), 'a') → ['a','a','a'] |
| pull、pullAll、pullAt | 原地移除元素 | pull([1,2,3,4], 2, 4) → [1,3] |
| remove | 原地移除满足条件的元素 | remove([1,2,3], n => n > 1) → 移除 [2,3],返回 [2,3] |
| slice | 截取(不修改原数组) | slice([1,2,3,4], 1, 3) → [2,3] |
| sortedIndex、sortedIndexOf | 有序数组操作 | sortedIndex([10,20,30], 25) → 2 |
| without | 排除指定值(非原地) | without([1,2,3,4], 2, 4) → [1,3] |
| findIndex、findLastIndex | 查找索引 | findIndex([1,2,3], n => n > 1) → 1 |
import { chunk, uniqBy, intersection, flattenDeep } from 'lodash-es'
// 分页分块
const pages = chunk(dataList, 10)
// 按 id 去重
const uniqueUsers = uniqBy(userList, 'id')
// 求共同好友
const commonFriends = intersection(myFriends, theirFriends)
// 递归扁平嵌套数据
const flatList = flattenDeep(nestedData)
集合(Collection)
lodash-es 集合方法统一处理数组和对象,涵盖分组、排序、查找、转换等数据操作。
| 函数 | 简要说明 | 示例 |
|---|---|---|
| forEach、forEachRight | 遍历 | forEach([1,2], n => console.log(n)) |
| map(coll, iter) | 映射 | map([1,2,3], n => n * 2) → [2,4,6] |
| filter(coll, pred) | 过滤 | filter([1,2,3], n => n > 1) → [2,3] |
| reject(coll, pred) | 排除满足条件的 | reject([1,2,3], n => n > 1) → [1] |
| find(coll, pred)、findLast | 查找第一个匹配 | find([1,2,3], n => n > 1) → 2 |
| every(coll, pred) | 是否全部满足 | every([1,2,3], n => n > 0) → true |
| some(coll, pred) | 是否有任一满足 | some([1,2,3], n => n > 2) → true |
| countBy(coll, iter) | 按条件计数分组 | countBy(['a','b','a']) → {a:2,b:1} |
| keyBy(coll, iter) | 按 key 组装对象 | keyBy([{id:1},{id:2}], 'id') → {1:{id:1},2:{id:2}} |
| groupBy | 按条件分组 | groupBy([1, 2, 3, 4, 5], n => n % 2 === 0 ? 'even' : 'odd') |
| sortBy | 排序 | sortBy(users, ['name','age']) |
| includes(coll, val, fromIndex) | 是否包含 | includes({a:1,b:2}, 2) → true |
| size(coll) | 集合大小 | size({a:1,b:2}) → 2 |
import { groupBy, orderBy, keyBy, countBy } from 'lodash-es'
// 按部门分组员工
const employeesByDept = groupBy(employees, 'department')
// 按年龄降序、姓名升序排序
const sorted = orderBy(users, ['age', 'name'], ['desc', 'asc'])
// 转 id 为 key 的映射,O(1) 查找
const userMap = keyBy(userList, 'id')
const user = userMap[targetId] // 快速查找
// 统计各角色人数
const roleCount = countBy(users, 'role')
函数(Function)
函数工具包括防抖、节流、缓存等性能优化利器,是前端交互优化的常用手段。
| 函数 | 简要说明 | 示例 |
|---|---|---|
| debounce(fn, wait, options) | 防抖 | debounce(handleSearch, 300) |
| throttle(fn, wait, options) | 节流 | throttle(onScroll, 200) |
| once(fn) | 只执行一次 | once(initApp) |
| before(n, fn) | 最多执行 n 次 | before(3, log) |
| delay(fn, wait, ...args) | 延迟执行 | delay(() => console.log('hi'), 1000) |
import { debounce, throttle } from 'lodash-es'
// 防抖:输入停止 300ms 后触发搜索
const handleSearch = debounce((keyword) => {
fetchSearchResults(keyword)
}, 300)
// 节流:滚动加载,1 秒内最多触发一次
const handleScroll = throttle(() => {
loadMoreData()
}, 1000)
语言(Lang)
类型判断、比较、转换。
| 函数 | 简要说明 | 示例 |
|---|---|---|
| isEqual | 深度比较相等 | isEqual({a:{b:1}}, {a:{b:1}}) → true |
| isMatch | 对象是否匹配子集 | isMatch({a:1,b:2}, {a:1}) → true |
| isEmpty | 是否为空 | isEmpty({}) → true; isEmpty([1]) → false |
| isArray | 是否数组 | isArray([1]) → true |
| isBoolean | 是否布尔值 | isBoolean(true) → true |
| isFunction | 是否函数 | isFunction(() => {}) → true |
| isInteger | 是否整数 | isInteger(3) → true |
| isNil | 是否 null/undefined | isNil(null) → true |
| isNumber | 是否数字 | isNumber(3) → true |
| isObject | 对象判断 | isPlainObject({}) → true; isPlainObject(new Date()) → false |
| isString | 字符串/符号判断 | isString('abc') → true |
| isDate | 特殊类型判断 | isDate(new Date()) → true |
| isMap、isSet | 集合类型判断 | isSet(new Set()) → true |
| isArrayBuffer、isTypedArray | 二进制类型判断 | isTypedArray(new Uint8Array()) → true |
| eq(a, b) | 严格相等 | eq(NaN, NaN) → true(区别于 ===) |
| gt、gte、lt、lte | 大于/大于等于/小于/小于等于 | gt(3, 1) → true |
| castArray | 将值转为数组 | castArray(1) → [1]; castArray([1]) → [1] |
| toArray(val) | 转为数组 | toArray({a:1,b:2}) → [1,2] |
| toInteger、toNumber toLength、toSafeInteger | 类型转换 | toInteger(3.7) → 3 |
数学(Math)
| 函数 | 简要说明 | 示例 |
|---|---|---|
| add、subtract、multiply、divide | 四则运算 | add(1, 2) → 3 |
| ceil、floor、round | 取整/四舍五入 | ceil(4.006, 2) → 4.01 |
| max、maxBy、min、minBy | 最大最小值 | maxBy([{n:1},{n:3},{n:2}], 'n') → {n:3} |
| mean | 平均值 | mean([4,6]) → 5 |
| sum | 求和 | sumBy([{n:1},{n:3}], 'n') → 4 |
数字(Number)
| 函数 | 简要说明 | 示例 |
|---|---|---|
| clamp(num, min, max) | 限制在范围内 | clamp(15, 0, 10) → 10 |
| inRange(num, start, end) | 是否在范围内 | inRange(3, 2, 4) → true |
| random(min, max, floating) | 随机数 | random(1, 10) → 5 |
对象(Object)
对象处理是 lodash 最核心的能力之一,涵盖安全取值赋值、深拷贝、属性筛选等,是日常开发中减少样板代码的利器。
| 函数 | 简要说明 | 示例 |
|---|---|---|
| get(obj, path, default) | 安全取值,路径不存在时返回默认值 | get({a:{b:1}}, 'a.b.c', 'N/A') → 'N/A' |
| set(obj, path, val) | 安全深度赋值 | set({}, 'a.b.c', 3) → {a:{b:{c:3}}} |
| has(obj, path) | 判断属性是否存在 | has({a:{b:1}}, 'a.b') → true |
| unset(obj, path) | 删除属性 | unset({a:{b:1}}, 'a.b') → true |
| merge(obj, ...sources) | 深度合并 | merge({a:1},{b:{c:2}}) → {a:1,b:{c:2}} |
| assign(obj, ...sources) | 浅合并 | assign({a:1},{b:2}) → {a:1,b:2} |
| pick(obj, paths) | 提取指定属性 | pick({a:1,b:2,c:3},['a','c']) → {a:1,c:3} |
| omit(obj, paths) | 排除指定属性 | omit({a:1,b:2,c:3},['b']) → {a:1,c:3} |
| keys(obj)、 values | 获取键/值 | keys({a:1,b:2}) → ['a','b'] |
| entries(obj) | 获取 [key, value] 对 | entries({a:1}) → [['a',1]] |
| fromPairs(pairs) | 数组转对象 | fromPairs([['a',1]]) → {a:1} |
| defaults(obj, ...sources) | 填充默认值 | defaults({a:1},{a:3,b:2}) → {a:1,b:2} |
| findKey(obj, pred) / findLastKey | 查找 key | findKey({a:1,b:2}, v => v > 1) → 'b' |
import { get, set, cloneDeep, omit, merge } from 'lodash-es'
// 安全取值,避免 Cannot read property 错误
const userName = get(response, 'data.user.name', '未知用户')
// 深拷贝表单数据
const formCopy = cloneDeep(originalForm)
// 剔除敏感字段后返回给前端
const safeUser = omit(user, ['password', 'salt'])
// 深度合并配置
const finalConfig = merge({}, defaultConfig, userConfig)
字符串(String)
字符串处理涵盖命名格式转换、填充、截断等实用工具。
| 函数 | 简要说明 | 示例 |
|---|---|---|
| camelCase | 转驼峰 | camelCase('foo_bar-baz') → 'fooBarBaz' |
| kebabCase | 转短横线 | kebabCase('fooBar') → 'foo-bar' |
| snakeCase | 转下划线 | snakeCase('fooBar') → 'foo_bar' |
| lowerCase、upperCase | 全小写/全大写(按单词分隔) | lowerCase('FooBar') → 'foo bar' |
| capitalize | 首字母大写其余小写 | capitalize('hello') → 'Hello' |
| upperFirst、lowerFirst | 仅首字母大小写 | upperFirst('hello world') → 'Hello world' |
| startCase | 每个单词首字母大写 | startCase('--foo-bar--') → 'Foo Bar' |
| debar | 去除变音符号 | deburr('déjà vu') → 'deja vu' |
| startsWith、endsWith | 前缀/后缀判断 | startsWith('hello','he') → true |
| escape、unescape | HTML 转义/反转义 | escape('<div>') → '<div>' |
| escapeRegExp | 转义正则特殊字符 | escapeRegExp('(abc)') → '$abc$' |
| truncate | 截断 | truncate('hello world',{length:5}) → 'he...' |
| repeat | 重复 | repeat('ab', 3) → 'ababab' |
| padStart、padEnd | 填充 | padStart('5',3,'0') → '005' |
| pad | 两端填充 | pad('abc', 8, '_-') → '_-abc_-_' |
| trim、trimStart、trimEnd | 去除首尾空白 | trim(' hello ') → 'hello' |
| split(str, sep, limit) | 分割字符串 | split('a-b-c','-',2) → ['a','b'] |
| template(str) | 编译模板 | template('hi <%= name %>')({name:'Tom'}) → 'hi Tom' |
| words(str) | 提取单词数组 | words('hello world') → ['hello','world'] |
import { camelCase, kebabCase, snakeCase, padStart } from 'lodash-es'
// 后端返回下划线字段转驼峰
const key = camelCase('user_name') // 'userName'
// 生成 CSS 类名
const className = kebabCase('UserProfile') // 'user-profile'
// 日期补零
const month = padStart(String(5), 2, '0') // '05'
总结
Lodash-es 是现代 JavaScript 开发中不可或缺的工具库。通过按需导入和合理使用,可以显著提升开发效率和代码质量。记住始终使用 ES 模块语法导入,并根据项目需求选择合适的函数,避免不必要的依赖。