# Lodash这些方法真好用,代码量直接减半

3 阅读3分钟

项目里总有些通用的数据处理逻辑,自己写容易出bug,用Lodash又觉得只用了冰山一角。

今天整理一批真正高频、真正好用的Lodash方法,都是我在项目里反复用到的。

对象处理

get:安全取值,不用再写一堆三元

// 原生写法
const name = res && res.data && res.data.user && res.data.user.name;

// Lodash
const name = _.get(res, 'data.user.name', '默认值');

// 数组下标也支持
const first = _.get(list, '[0].name');

这是我用得最多的一个方法,深层次的接口返回,用它省心。

pick / omit:筛选字段

const user = { id: 1, name: '张三', password: 'xxx', token: 'abc' };

// 只保留指定字段
_.pick(user, ['id', 'name']);
// { id: 1, name: '张三' }

// 排除指定字段(防止敏感信息返回前端)
_.omit(user, ['password', 'token']);
// { id: 1, name: '张三' }

merge / defaults:合并配置

const defaultConfig = {
    pageSize: 10,
    orderBy: 'createTime',
    orderDir: 'desc',
    filters: { status: 'ALL' }
};

const userConfig = {
    pageSize: 20,
    filters: { status: 'PAID' }
};

_.merge({}, defaultConfig, userConfig);
// { pageSize: 20, orderBy: 'createTime', orderDir: 'desc', filters: { status: 'PAID' } }

merge会深合并,assign只会浅覆盖。配置合并的场景一定要用merge。

数组处理

uniqBy:按字段去重

const list = [
    { id: 1, name: 'A' },
    { id: 2, name: 'B' },
    { id: 1, name: 'A副本' }
];

_.uniqBy(list, 'id');
// [{ id: 1, name: 'A' }, { id: 2, name: 'B' }]

比new Set()好用多了,Set只能对基本类型去重。

groupBy:分组

const orders = [
    { id: 1, status: 'PAID' },
    { id: 2, status: 'UNPAID' },
    { id: 3, status: 'PAID' }
];

_.groupBy(orders, 'status');
// {
//   PAID: [{ id: 1 }, { id: 3 }],
//   UNPAID: [{ id: 2 }]
// }

sortBy:多字段排序

_.sortBy(list, ['status', 'createTime']);
// 先按status排,相同再按createTime排

chunk:数组分块

_.chunk([1, 2, 3, 4, 5, 6, 7], 3);
// [[1,2,3], [4,5,6], [7]]

批量请求的时候特别有用:

const batches = _.chunk(ids, 100);
for (const batch of batches) {
    await api.batchQuery(batch);
}

difference / intersection:集合运算

const oldIds = [1, 2, 3, 4];
const newIds = [3, 4, 5, 6];

_.difference(newIds, oldIds);      // [5, 6] 新增的
_.difference(oldIds, newIds);      // [1, 2] 删除的
_.intersection(oldIds, newIds);    // [3, 4] 共有的

做数据同步的时候,这三个方法能省一堆代码。

函数工具

debounce / throttle

const search = _.debounce(function(keyword) {
    api.search(keyword);
}, 300);

const onScroll = _.throttle(function() {
    updatePosition();
}, 200);

比自己手写省事,而且cancel/flush这些方法都有。

memoize:缓存计算结果

const expensiveCalc = _.memoize(function(n) {
    console.log('计算中...');
    return n * n;
});

expensiveCalc(5); // 计算中... 25
expensiveCalc(5); // 25(直接返回缓存)

注意:默认只缓存第一个参数,多参数要自己写resolver。

const calc = _.memoize(
    (a, b) => a + b,
    (a, b) => `${a}-${b}`  // 自定义缓存key
);

cloneDeep:深拷贝

const copy = _.cloneDeep(original);

比JSON.parse(JSON.stringify())靠谱,能处理Date、RegExp、循环引用。

判断工具

_.isEmpty([]);          // true
_.isEmpty({});          // true
_.isEmpty('');          // true
_.isEmpty(null);        // true
_.isEmpty(0);           // true(这个要注意)

_.isEqual({ a: 1 }, { a: 1 });   // true(深比较)
_.isNil(null);          // true(null或undefined)
_.isPlainObject({});    // true(纯对象)

_.isEmpty(0)返回true这个坑我踩过,数字0会被当成空。判断数组空还是用arr.length === 0更稳妥。

按需引入

Lodash全量引入有70KB+,按需引入能砍到几KB:

// 不好
import _ from 'lodash';

// 好
import get from 'lodash/get';
import debounce from 'lodash/debounce';

// 更好(配合babel-plugin-lodash自动处理)
import { get, debounce } from 'lodash';

现在很多方法原生JS也能实现了(Object.groupBy、Array.prototype.at),但Lodash的兼容性和便利性依然有优势。选几个高频的用起来,开发效率提升很明显。