疯狂餐厅
86.88M · 2026-03-21
lodash 和 lodash-es 都是 JavaScript 实用工具库,提供数组、对象、字符串等数据类型的操作函数。它们的关系是:
require() 导入import 导入核心差异:lodash-es 不是简单的格式转换,而是从源码层面重构了模块化结构,让现代打包工具(Webpack、Rollup、Vite)能够进行 Tree Shaking(摇树优化),只打包用到的函数。
// lodash 的 _.debounce 函数
module.exports = function debounce(func, wait, options) {
// ... 实现代码
return debounced;
};
// 整个 lodash 导出
module.exports = {
debounce: require('./debounce'),
throttle: require('./throttle'),
// ... 几百个函数
};
// lodash-es 的 debounce.js
export default function debounce(func, wait, options) {
// ... 实现代码
return debounced;
}
// 每个函数独立文件,支持按需导入
// debounce.js, throttle.js, cloneDeep.js 等
关键区别:lodash 将所有函数打包在一个大对象里,lodash-es 将每个函数放在独立文件中。
# 安装 lodash-es
npm install lodash-es
# 或者安装特定函数
npm install lodash.debounce lodash.throttle
project/
├── src/
│ ├── main.js # 主入口文件
│ └── utils.js # 工具函数
├── package.json
└── webpack.config.js
使用 lodash(传统方式)
// 导入整个 lodash(几百 KB)
const _ = require('lodash');
// 只使用 debounce 函数,但打包了整个 lodash
const debouncedFunc = _.debounce(() => {
console.log('防抖函数');
}, 300);
使用 lodash-es(现代方式)
// 按需导入特定函数(Webpack 会自动 Tree Shaking)
import { debounce, throttle } from 'lodash-es';
// 或者只导入需要的函数
import debounce from 'lodash-es/debounce';
import throttle from 'lodash-es/throttle';
const debouncedFunc = debounce(() => {
console.log('防抖函数');
}, 300);
const throttledFunc = throttle(() => {
console.log('节流函数');
}, 300);
// webpack.config.js
module.exports = {
mode: 'production',
entry: './src/main.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
optimization: {
usedExports: true, // 启用 Tree Shaking
minimize: true // 代码压缩
}
};
创建测试文件:
// test-lodash.js
const _ = require('lodash');
console.log(_.debounce);
// test-lodash-es.js
import { debounce } from 'lodash-es';
console.log(debounce);
运行打包命令:
# 打包 lodash 版本
npx webpack --entry ./test-lodash.js --output-filename bundle-lodash.js
# 打包 lodash-es 版本
npx webpack --entry ./test-lodash-es.js --output-filename bundle-lodash-es.js
# 查看文件大小
ls -lh dist/*.js
预期结果:
bundle-lodash.js:~70KB(整个 lodash)bundle-lodash-es.js:~2KB(仅 debounce 函数)ES Module 的 import 和 export 是静态的,打包工具可以在编译时分析:
查看 lodash-es 的 cloneDeep 函数源码:
// lodash-es/cloneDeep.js
import baseClone from './.internal/baseClone.js';
/** 用于标识深拷贝 */
const CLONE_DEEP_FLAG = 1;
const CLONE_SYMBOLS_FLAG = 4;
function cloneDeep(value) {
return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG);
}
export default cloneDeep;
关键点:每个函数都是独立的 ES Module,有自己的依赖关系图。
// Webpack 的 Tree Shaking 过程
1. 解析 import 语句 → 找到 lodash-es/debounce
2. 分析 debounce.js 的依赖 → 找到内部依赖
3. 标记使用到的函数 → debounce 被标记为 used
4. 移除未标记的函数 → 其他函数被移除
5. 生成最终 bundle → 只包含 debounce 及其依赖
// performance-test.js
import { debounce, throttle, cloneDeep } from 'lodash-es';
// 对比
const _ = require('lodash');
// 测试函数
function testDebounce() {
const start = performance.now();
for (let i = 0; i < 10000; i++) {
const fn = debounce(() => {}, 100);
fn();
}
return performance.now() - start;
}
// 运行测试
console.log('lodash-es debounce:', testDebounce(), 'ms');
| 使用场景 | lodash 体积 | lodash-es 体积 | 优化比例 |
|---|---|---|---|
| 只使用 debounce | 72KB | 1.8KB | 97.5%↓ |
| 使用 5 个常用函数 | 72KB | 8.2KB | 88.6%↓ |
| 使用 10 个函数 | 72KB | 15.4KB | 78.6%↓ |
| 使用全部函数 | 72KB | 72KB | 0% |
// 推荐:按需导入特定函数
import debounce from 'lodash-es/debounce';
import throttle from 'lodash-es/throttle';
// 不推荐:导入整个库
import _ from 'lodash-es';
// 特殊情况:需要很多函数时
import { debounce, throttle, cloneDeep, isEqual, memoize } from 'lodash-es';
从 lodash 迁移到 lodash-es:
// 之前
const _ = require('lodash');
_.debounce(func, 300);
// 之后
import debounce from 'lodash-es/debounce';
debounce(func, 300);
// 或者批量替换
import { debounce, throttle, cloneDeep } from 'lodash-es';
// Node.js 需要启用 ES Module
// package.json
{
"type": "module" // 添加这一行
}
// 或���使用 .mjs 扩展名
import debounce from 'lodash-es/debounce.mjs';
// tsconfig.json
{
"compilerOptions": {
"module": "esnext", // 使用 ES Module
"moduleResolution": "node",
"allowSyntheticDefaultImports": true
}
}
<!-- 需要支持 type="module" 的浏览器 -->
<script type="module">
import debounce from 'https://unpkg.com/lodash-es/debounce.js';
const debounced = debounce(() => {
console.log('Hello from lodash-es!');
}, 300);
</script>
lodash 到 lodash-es 的升级,远不止是后缀变化:
迁移建议:
最后提醒:lodash-es 不是银弹,如果项目需要大量 lodash 函数,直接导入整个库可能更合适。但对于大多数现代前端项目,lodash-es + Tree Shaking 是最佳选择。
如果对你有用,欢迎点赞、收藏、关注! 下一篇我们将深入分析 antd 组件的源码实现。
参考资料: