🔧 Lodash 实用工具库完整指南
Lodash 是一个一致性、模块化、高性能的 JavaScript 实用工具库。通过降低 array、number、objects、string 等的使用难度,让 JavaScript 开发变得更简单高效。
📚 本章内容
全面学习 Lodash 的核心 API,掌握数组、对象、字符串、函数等操作的最佳实践。
🌟 Lodash 简介
✨ 核心优势
特性 | 说明 | 优势 |
---|---|---|
一致性 | 统一的 API 设计 | 降低学习成本,提高开发效率 |
模块化 | 支持按需引入 | 减少包体积,优化性能 |
高性能 | 优化的算法实现 | 比原生方法更快的执行速度 |
兼容性 | 跨浏览器兼容 | 统一不同环境的行为差异 |
🎯 适用场景
- 🔄 遍历操作 - array、object 和 string 的高效遍历
- 🔧 数据处理 - 对值进行操作和检测
- ⚡ 函数式编程 - 创建符合功能的函数
- 🛠️ 工具函数 - 常用的辅助函数集合
📊 数组操作方法
🔪 数组分割与处理
_.chunk() - 数组分块
将数组拆分成指定长度的区块:
javascript
/**
* 将数组拆分成多个 size 长度的区块
* @param {Array} array - 需要处理的数组
* @param {number} [size=1] - 每个数组区块的长度
* @returns {Array} 包含拆分区块的新数组
*/
_.chunk(array, [size=1])
// 📝 使用示例
_.chunk(['a', 'b', 'c', 'd'], 2)
// => [['a', 'b'], ['c', 'd']]
_.chunk(['a', 'b', 'c', 'd'], 3)
// => [['a', 'b', 'c'], ['d']]
_.chunk(['a', 'b', 'c', 'd'], 5)
// => [['a', 'b', 'c', 'd']]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
_.compact() - 移除假值
创建一个移除所有假值元素的新数组:
javascript
/**
* 创建一个新数组,包含原数组中所有的非假值元素
* 假值包括:false, null, 0, "", undefined, NaN
* @param {Array} array - 需要处理的数组
* @returns {Array} 去除假值后的新数组
*/
_.compact(array)
// 📝 使用示例
_.compact([0, 1, false, 2, '', 3, null, undefined, NaN])
// => [1, 2, 3]
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
🔍 数组差异与交集
_.difference() - 数组差异
方法 | 说明 | 参数 | 返回值 |
---|---|---|---|
_.difference() | 基本差异比较 | (array, [values]) | 过滤值后的新数组 |
_.differenceBy() | 使用迭代器比较 | (array, [values], [iteratee]) | 过滤值后的新数组 |
_.differenceWith() | 使用比较器比较 | (array, [values], [comparator]) | 过滤值后的新数组 |
javascript
// 🔹 基本差异比较
_.difference([3, 2, 1], [4, 2])
// => [3, 1]
// 🔹 使用迭代器比较
_.differenceBy([3.1, 2.2, 1.3], [4.4, 2.5], Math.floor)
// => [3.1, 1.3]
// 属性简写形式
_.differenceBy([{ x: 2 }, { x: 1 }], [{ x: 1 }], 'x')
// => [{ 'x': 2 }]
// 🔹 使用比较器
const objects = [
{ x: 1, y: 2 },
{ x: 2, y: 1 }
]
_.differenceWith(objects, [{ x: 1, y: 2 }], _.isEqual)
// => [{ 'x': 2, 'y': 1 }]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
_.intersection() - 数组交集
javascript
/**
* 创建唯一值的数组,包含所有给定数组都包含的元素
* @param {...Array} [arrays] - 待检查的数组
* @returns {Array} 包含所有传入数组交集元素的新数组
*/
_.intersection([arrays])
// 📝 使用示例
_.intersection([2, 1], [4, 2], [1, 2])
// => [2]
// 使用迭代器
_.intersectionBy([2.1, 1.2], [4.3, 2.4], Math.floor)
// => [2.1]
// 属性简写形式
_.intersectionBy([{ x: 1 }], [{ x: 2 }, { x: 1 }], 'x')
// => [{ 'x': 1 }]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
✂️ 数组裁剪方法
_.drop() 系列方法
方法 | 说明 | 方向 | 条件 |
---|---|---|---|
_.drop() | 去除前面 n 个元素 | 从前往后 | 固定数量 |
_.dropRight() | 去除后面 n 个元素 | 从后往前 | 固定数量 |
_.dropWhile() | 去除前面满足条件的元素 | 从前往后 | 条件判断 |
_.dropRightWhile() | 去除后面满足条件的元素 | 从后往前 | 条件判断 |
javascript
// 🔹 固定数量裁剪
_.drop([1, 2, 3]) // => [2, 3]
_.drop([1, 2, 3], 2) // => [3]
_.drop([1, 2, 3], 0) // => [1, 2, 3]
_.dropRight([1, 2, 3]) // => [1, 2]
_.dropRight([1, 2, 3], 2) // => [1]
// 🔹 条件裁剪
const users = [
{ user: 'barney', active: true },
{ user: 'fred', active: false },
{ user: 'pebbles', active: false }
]
// 去除开头不活跃的用户
_.dropWhile(users, function(o) { return !o.active })
// => objects for ['pebbles']
// 使用属性匹配简写
_.dropWhile(users, { user: 'barney', active: false })
// => objects for ['fred', 'pebbles']
// 使用属性路径简写
_.dropWhile(users, ['active', false])
// => objects for ['pebbles']
// 使用属性简写
_.dropWhile(users, 'active')
// => objects for ['barney', 'fred', 'pebbles']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
🔧 对象操作方法
📊 对象属性操作
javascript
// 🔹 获取对象的键
_.keys({ a: 1, b: 2, c: 3 })
// => ['a', 'b', 'c']
// 🔹 获取对象的值
_.values({ a: 1, b: 2, c: 3 })
// => [1, 2, 3]
// 🔹 获取键值对数组
_.toPairs({ a: 1, b: 2, c: 3 })
// => [['a', 1], ['b', 2], ['c', 3]]
// 🔹 从键值对数组创建对象
_.fromPairs([['a', 1], ['b', 2], ['c', 3]])
// => { a: 1, b: 2, c: 3 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
🔄 对象合并与克隆
javascript
// 🔹 浅合并
_.assign({ a: 1 }, { b: 2 }, { c: 3 })
// => { a: 1, b: 2, c: 3 }
// 🔹 深合并
_.merge({ a: [1] }, { a: [2, 3] })
// => { a: [1, 2, 3] }
// 🔹 浅克隆
_.clone({ a: 1, b: { c: 2 } })
// 🔹 深克隆
_.cloneDeep({ a: 1, b: { c: 2 } })
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
🔤 字符串操作方法
✂️ 字符串格式化
方法 | 说明 | 示例 |
---|---|---|
_.camelCase() | 驼峰命名 | 'foo bar' → 'fooBar' |
_.kebabCase() | 短横线命名 | 'Foo Bar' → 'foo-bar' |
_.snakeCase() | 下划线命名 | 'Foo Bar' → 'foo_bar' |
_.startCase() | 首字母大写 | 'foo bar' → 'Foo Bar' |
_.upperFirst() | 首字母大写 | 'fred' → 'Fred' |
_.lowerFirst() | 首字母小写 | 'Fred' → 'fred' |
javascript
// 📝 字符串格式转换示例
_.camelCase('Foo Bar') // => 'fooBar'
_.camelCase('--foo-bar--') // => 'fooBar'
_.camelCase('__FOO_BAR__') // => 'fooBar'
_.kebabCase('Foo Bar') // => 'foo-bar'
_.kebabCase('fooBar') // => 'foo-bar'
_.kebabCase('__FOO_BAR__') // => 'foo-bar'
_.snakeCase('Foo Bar') // => 'foo_bar'
_.snakeCase('fooBar') // => 'foo_bar'
_.snakeCase('--FOO-BAR--') // => 'foo_bar'
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
🔍 字符串检测
javascript
// 🔹 开始/结束检测
_.startsWith('abc', 'a') // => true
_.startsWith('abc', 'b', 1) // => true
_.endsWith('abc', 'c') // => true
_.endsWith('abc', 'b', 2) // => true
// 🔹 包含检测
_.includes('abcd', 'bc') // => true
_.includes('abcd', 'e') // => false
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
⚡ 函数操作方法
🕐 防抖与节流
javascript
// 🔹 防抖函数 - 延迟执行,重复调用会重置计时器
const debouncedSave = _.debounce(function() {
console.log('保存数据')
}, 1000)
// 用户停止输入1秒后才执行保存
input.addEventListener('input', debouncedSave)
// 🔹 节流函数 - 限制执行频率
const throttledScroll = _.throttle(function() {
console.log('滚动处理')
}, 100)
// 每100ms最多执行一次
window.addEventListener('scroll', throttledScroll)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
🔄 函数包装
javascript
// 🔹 一次性函数
const initialize = _.once(function() {
console.log('初始化完成')
})
initialize() // => '初始化完成'
initialize() // => 不会再次执行
// 🔹 记忆化函数
const memoizedAdd = _.memoize(function(a, b) {
console.log('计算中...')
return a + b
})
memoizedAdd(1, 2) // => 计算中... 3
memoizedAdd(1, 2) // => 3 (使用缓存)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
🔍 集合操作方法
📊 数据统计
javascript
// 🔹 分组统计
const users = [
{ name: 'Alice', age: 25, active: true },
{ name: 'Bob', age: 30, active: false },
{ name: 'Charlie', age: 25, active: true }
]
// 按年龄分组
_.groupBy(users, 'age')
// => { 25: [...], 30: [...] }
// 按活跃状态计数
_.countBy(users, 'active')
// => { true: 2, false: 1 }
// 按条件分割
_.partition(users, 'active')
// => [[active users], [inactive users]]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
🔄 数据转换
javascript
// 🔹 映射转换
_.map([1, 2, 3], n => n * 2)
// => [2, 4, 6]
// 🔹 过滤筛选
_.filter([1, 2, 3, 4], n => n % 2 === 0)
// => [2, 4]
// 🔹 查找元素
_.find(users, { active: true })
// => 第一个活跃用户
// 🔹 归约计算
_.reduce([1, 2, 3], (sum, n) => sum + n, 0)
// => 6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
🎯 实用工具方法
🔍 类型检测
方法 | 检测类型 | 示例 |
---|---|---|
_.isArray() | 数组 | _.isArray([1, 2, 3]) → true |
_.isObject() | 对象 | _.isObject({}) → true |
_.isString() | 字符串 | _.isString('abc') → true |
_.isNumber() | 数字 | _.isNumber(123) → true |
_.isBoolean() | 布尔值 | _.isBoolean(true) → true |
_.isFunction() | 函数 | _.isFunction(() => {}) → true |
_.isDate() | 日期 | _.isDate(new Date()) → true |
_.isRegExp() | 正则 | _.isRegExp(/abc/) → true |
_.isEmpty() | 空值 | _.isEmpty([]) → true |
_.isNil() | null/undefined | _.isNil(null) → true |
🔧 实用函数
javascript
// 🔹 生成唯一ID
_.uniqueId() // => '1'
_.uniqueId('user_') // => 'user_2'
// 🔹 随机数生成
_.random(0, 5) // => 0到5之间的随机整数
_.random(1.2, 5.2) // => 1.2到5.2之间的随机浮点数
// 🔹 数组洗牌
_.shuffle([1, 2, 3, 4])
// => [4, 1, 3, 2] (随机顺序)
// 🔹 随机抽样
_.sample([1, 2, 3, 4]) // => 随机一个元素
_.sampleSize([1, 2, 3, 4], 2) // => 随机两个元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
📈 性能优化技巧
🎯 按需引入
javascript
// ❌ 全量引入 (不推荐)
import _ from 'lodash'
// ✅ 按需引入 (推荐)
import debounce from 'lodash/debounce'
import throttle from 'lodash/throttle'
import cloneDeep from 'lodash/cloneDeep'
// ✅ 使用 ES6 解构
import { debounce, throttle, cloneDeep } from 'lodash'
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
⚡ 链式调用
javascript
// 🔗 链式操作提高可读性
const result = _(users)
.filter('active')
.map('name')
.sortBy()
.take(5)
.value()
// 等价于
const result = _.take(
_.sortBy(
_.map(
_.filter(users, 'active'),
'name'
)
),
5
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
🎯 最佳实践
✅ 推荐做法
按需引入模块
javascript// ✅ 减少包体积 import debounce from 'lodash/debounce'
1
2使用链式调用
javascript// ✅ 提高可读性 _(data).filter().map().sortBy().value()
1
2利用简写形式
javascript// ✅ 属性简写 _.map(users, 'name') _.filter(users, { active: true })
1
2
3合理使用记忆化
javascript// ✅ 缓存昂贵的计算 const expensiveCalc = _.memoize(complexFunction)
1
2
❌ 避免的问题
过度使用 Lodash
javascript// ❌ 简单操作不需要 Lodash _.map([1, 2, 3], x => x * 2) // ✅ 使用原生方法 [1, 2, 3].map(x => x * 2)
1
2
3
4
5忽视性能影响
javascript// ❌ 在循环中重复创建函数 users.forEach(user => { const debouncedSave = _.debounce(save, 1000) }) // ✅ 在循环外创建 const debouncedSave = _.debounce(save, 1000) users.forEach(user => { debouncedSave(user) })
1
2
3
4
5
6
7
8
9
10
📚 相关资源
🚀 继续学习
掌握了 Lodash 基础后,建议学习函数式编程概念,以及如何在项目中合理使用工具库来提高开发效率。