lodash:高性能JavaScript工具函数库

介绍

Lodash 是 MIT协议、高性能JavaScript工具函数库,前身是 Underscore.js,作者 John‑David Dalton,提供 300+工具方法,专门处理数组、对象、函数、字符串、集合等常见操作,前端、Node.js都可以使用。

官方

github

中文文档

版本

主流稳定版 v4.x,是目前最广泛使用版本。

特点

  1. 边界容错能力强
    自动处理 null / undefined,访问深层属性不会直接抛出 Cannot read property 错误。

  2. 模块化
    有 CommonJS、ESM(lodash‑es)、fp函数式版本,支持按需引入,避免全量打包。

  3. 链式调用
    _.chain() 可以串联多个数据处理方法,简化连续转换逻辑。

  4. 兼容性好
    兼容现代浏览器、Node,兼容 IE11,抹平各环境JSAPI差异。

  5. 经过工业验证
    大量大厂项目使用,算法经过优化,比手写简易版本更健壮,处理嵌套对象、循环引用场景考虑周全。

包版本区别

包 模块格式 Tree‑shaking 说明
lodash CommonJS 不支持 Node老项目,import _ from 'lodash' 会引入完整库;可以手动导入单文件lodash/debounce做按需加载
lodash‑es ESM ✅支持 现代Vue/React/Vite/Webpack项目首选,打包器自动删除未使用函数,体积更小
lodash/fp 函数式版本 ‑ 数据放最后,自动柯里化,不可变,适合函数式编程风格项目

TS项目:lodash 搭配 @types/lodash;lodash‑es 搭配 @types/lodash‑es。

安装

pnpm 安装

普通版本
pnpm add lodash
pnpm add -D @types/lodash
现代项目(适合vue)

安装 lodash‑es

pnpm add lodash‑es
pnpm add -D @types/lodash‑es

导入方式

// ❌不推荐:全量引入lodash,打包体积大
import _ from 'lodash'

// ✅方式1:lodash‑es 直接解构,tree‑shaking生效(vite/webpack)
import { debounce, cloneDeep, get } from 'lodash‑es'

// ✅方式2:lodash(CJS)单独引入单个函数,避免引入全部库
import debounce from 'lodash/debounce'
import cloneDeep from 'lodash/cloneDeep'

// Node.js CommonJS
const _ = require('lodash')
const debounce = require('lodash/debounce')

六大模块高频API

1. 对象 Object

  • _.get(obj, path, defaultValue):安全读取深层属性,路径可以字符串'a.b.c'或者数组['a','b','c']
    const obj = {a:{b:1}}
    _.get(obj,'a.b',0) //1
    _.get(obj,'a.x.y',0) //0,不会报错
    
  • _.set(obj,path,value):安全设置深层属性
  • _.cloneDeep(value):递归深拷贝,支持对象、数组、Date、RegExp;注意不能拷贝函数、循环引用会报错
  • _.merge(obj1,obj2):深度合并对象(区别于Object.assign浅合并)
  • _.pick(obj,['name','age']):只保留指定key
  • _.omit(obj,['password']):剔除指定key
  • _.isEqual(a,b):深度对比两个值是否相等

2. 数组 Array

  • _.groupBy(list,key):按字段分组
    const list = [{type:'a',id:1},{type:'b',id:2},{type:'a',id:3}]
    _.groupBy(list,'type') 
    // {a:[{type:'a',id:1},{type:'a',id:3}], b:[{type:'b',id:2}]}
    
  • _.sortBy(list,key):按字段排序,返回新数组,不修改原数组
  • _.uniqBy(list,key):按对象字段去重
  • _.difference / intersection / union:集合差集、交集、并集
  • _.partition(list,fn):把数组分成满足条件、不满足条件两组
  • _.compact(arr):过滤掉null,undefined,false,0,''假值

3. 函数 Function(最常用)

  • _.debounce(fn,wait):防抖,多次触发合并成一次执行(搜索框输入)
  • _.throttle(fn,wait):节流,单位时间最多执行一次(滚动、resize)

    ⚠️React/Vue组件中,组件销毁务必调用.cancel()清除定时器,防止内存泄漏。

  • _.memoize(fn):缓存函数返回结果
  • _.curry(fn):柯里化

4. Lang 类型判断

_.isNil(val) // 判断 null / undefined
_.isEmpty(val) // 判断空对象、空数组、空字符串
_.isObject() _.isArray() _.isString() _.isNumber()

5. String 字符串

_.trim、_.upperCase、_.camelCase(转驼峰)、_.snakeCase

6. 链式调用 chain

const data = _.chain(list)
  .filter(x=>x.age>18)
  .sortBy('age')
  .map('name')
  .value() //必须调用.value()取出结果

⚠️v4版本已经移除惰性求值,链式只是语法糖,不会提升性能。

lodash vs 现代原生JS

ES6+很多能力原生已经实现,不需要一味使用lodash。

功能 Lodash写法 现代原生JS
安全读取深层属性 _.get(obj,'a.b.c') obj?.a?.b?.c
数组去重 _.uniq(arr) [...new Set(arr)]
深拷贝 _.cloneDeep(obj) structuredClone(obj)(不支持函数)
对象取值过滤 _.pick() 需要手写reduce
防抖节流 _.debounce / _.throttle 没有原生API,lodash依然首选
对象深度合并 _.merge() 无原生,需要手写递归
对象深度相等判断 _.isEqual() 无原生

结论:

  • 简单数组map/filter/find优先原生
  • 防抖节流、深合并、深度相等、groupBy、pick/omit、安全路径取值 仍然非常适合lodash。

优点与缺点

优点

  1. 大量成熟工具,不用手写重复逻辑,减少bug
  2. 大量边界情况已经处理,null、undefined、嵌套对象
  3. API统一,跨环境行为一致
  4. 文档完善,社区庞大

缺点

  1. 全量引入包体积大;必须注意导入方式,优先lodash‑es或者单文件导入
  2. ES标准持续迭代,部分API已经有原生替代
  3. 增加项目依赖;小项目如果只用一两个方法可以考虑手写实现

应用场景

Lodash 本质就是弥补 JS 原生 API 的短板,原生能简单搞定的就不用它;原生处理麻烦、边界多、需要写重复工具函数的场景,就是 Lodash 的主场。

1. 对象处理(后台返回嵌套JSON最常用)

后端返回复杂嵌套接口数据,经常存在字段缺失、null/undefined。

  1. 安全读取嵌套属性 _.get,避免 Cannot read properties of undefined。几乎不用,原生已经支持
  2. 深拷贝 cloneDeep:复制复杂对象/数组,Vue/React 状态备份、表单数据备份。
  3. 深度合并对象 merge:多层配置合并、多接口返回数据融合(Object.assign 只能浅合并)
  4. 字段筛选 pick / omit:过滤对象属性,剔除敏感字段、只保留需要提交的字段。
  5. 深度相等对比 isEqual:对比两个复杂对象/数组是否完全相等,表单校验、状态变更判断。

原生局限: ?. 只能读取,不能安全 set;没有原生深合并、没有原生深度对象比较。

2. 数组集合处理

前端拿到后端列表,做转换、分组、去重、筛选。

  1. 分组 groupBy:把列表按类型、状态分组,比如订单按状态分组,人员按部门分组。
  2. 对象数组去重 uniqBy:根据 id/name 去重对象数组,Set 只能处理简单基本类型。
  3. 集合运算 union / difference / intersection:求并集、差集、交集。
  4. 分割数组 partition:一次性把数组分成符合条件、不符合条件两组。
  5. 清理假值 compact:清除数组中 null undefined '' false 0。
  6. 排序 sortBy:多字段排序,返回新数组,不改动原数组。

原生局限: map/filter/reduce 可以实现,但要手写大量循环逻辑,边界需要自己处理。

3. 事件性能优化(高频!防抖节流)

JS没有原生防抖节流,这是 Lodash 使用最高频场景

  1. debounce 防抖:搜索框输入联想、表单输入校验,短时间多次触发只执行最后一次。
  2. throttle 节流:窗口滚动、窗口resize、鼠标移动,限制单位时间最多执行一次。

Vue/React组件销毁,调用 .cancel() 清除定时器,防止内存泄漏。

4. 函数工具

  1. memoize:缓存纯函数计算结果,重复相同参数直接取缓存,大数据计算优化。
  2. curry 柯里化:函数式编程,拆分多参函数。

5. 数据格式化、字符串转换

  1. 大小写转换、驼峰互转 camelCase / snakeCase,后端下划线字段 ↔ 前端驼峰字段互相转换。
  2. 字符串修剪、单词格式化。

6. 配置、默认值处理

  • _.defaults:给对象填充默认配置,缺失的key补上默认值,已有key保留原值。

7. 链式处理多步数据转换

_.chain(),连续做过滤、排序、映射,数据流水线处理。


哪些场景优先用 Lodash

  1. 接口返回嵌套复杂JSON,对象深拷贝、深度合并、深度比较、安全取值
  2. 对象数组操作:分组、按字段去重、集合运算
  3. 防抖、节流(几乎必用)
  4. 不想手写大量边界判断(自动兼容 null / undefined)

哪些场景不建议引入 Lodash

  1. 简单数组 map filter find,ES6原生完全够用
  2. 简单单层对象拷贝,直接展开运算符 {...obj}
  3. 简单基本类型数组去重 [...new Set(arr)]

项目举例

  1. 管理后台:大量表格数据,列表分组、筛选、字段过滤、表单深拷贝、配置合并
  2. 搜索页面:输入框 debounce 防抖请求接口
  3. 大屏可视化:滚动/resize事件节流;后端复杂数据做转换分组
  4. 表单系统:表单对象深拷贝、剔除密码等敏感字段、对比表单前后数据变化

原文出处:/show_1IX8UcZYMlU2.html