Read this in other languages: English
基于实际业务场景的轻量 diff 辅助库。提供对象与数组的结构化比对、主键列表 diff、排序感知以及通用递归 diff。
开发历程可以参考博客 手写一个业务数据比对库
- 针对业务场景的 diff,而非通用全量 patch
simpleObjDiff/isSimpleObjChange—— 对象浅层 diff 与快速变更判定simpleListDiff—— 基于主键key的数组 diff,内部使用Map索引,查找 O(1)- 可选
sortName,追踪位置变化 commonDiff—— 任意对象/数组递归 diff,保留层级结构- 零运行时依赖,ESM + CJS 双产物
npm install diff-helper
# 或
yarn add diff-helper
# 或
bun add diff-helper| 函数 | 用途 |
|---|---|
simpleObjDiff |
对象浅层 diff,返回差异字段 |
isSimpleObjChange |
判断两个对象是否发生变化(不返回 diff 结果) |
simpleListDiff |
按主键 diff 数组,返回增/删/改 |
commonDiff |
通用递归 diff,保留嵌套结构 |
对两个对象做浅层 diff,返回包含差异字段的对象。可传入 diffFun 自定义单字段比对逻辑。
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
newVal |
新对象 | Record<string, any> |
- |
oldVal |
老对象 | Record<string, any> |
- |
options.empty |
旧对象有、新对象无时的占位值 | null | '' |
null |
options.diffFun |
单字段比对函数,返回 null/undefined 时走默认比对 |
({ key, newPropVal, oldPropVal }) => any |
- |
options.needCopy |
是否对变更字段做 JSON 深拷贝 | boolean |
false |
import { simpleObjDiff } from 'diff-helper';
simpleObjDiff({
newVal: { b: 1, c: 12, e: '123', f: ['2131', 231, '1111'] },
oldVal: { b: 123, a: 123213, e: '123', f: ['2131', 231, '1111'] },
});
// => { b: 1, c: 12, a: null }
simpleObjDiff({
newVal: { b: 1, c: 12 },
oldVal: { b: 123, a: 123213 },
options: { empty: '' },
});
// => { b: 1, c: 12, a: '' }
simpleObjDiff({
newVal: { a: [12, 3, 4], b: 11 },
oldVal: { a: [1, 2, 3], c: 22 },
options: {
diffFun: ({ key, newPropVal, oldPropVal }) => {
if (key === 'a') {
return newPropVal.filter((item: any) => oldPropVal.includes(item));
}
return null; // 走默认 JSON 比对
},
},
});
// => { a: [3], b: 11, c: null }只判断两个对象是否有变化,不构造 diff 结果。当仅需判断是否需要触发后续流程(如发请求、重渲染)时更轻量。
import { isSimpleObjChange } from 'diff-helper';
isSimpleObjChange({
newVal: { a: 1, b: { c: 2 } },
oldVal: { a: 1, b: { c: 2 } },
});
// => false
isSimpleObjChange({
newVal: { a: 1 },
oldVal: { a: 1, b: 2 },
});
// => true (key 数不同)对带主键的数组做 diff,返回 addedLines / deletedLines / modifiedLines。传入 sortName 时额外返回 noChangeLines 并记录位置。
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
newVal |
新数组 | any[] |
- |
oldVal |
老数组 | any[] |
- |
options.key |
行主键字段名 | string |
'id' |
options.getChangedItem |
自定义变更判定;返回 null 表示未变更 |
({ newLine, oldLine }) => any |
内部用 simpleObjDiff |
options.sortName |
传入后额外输出 noChangeLines 并记录 index + 1 |
string |
'' |
import { simpleListDiff } from 'diff-helper';
// 不传 getChangedItem,内部用 simpleObjDiff
simpleListDiff({
newVal: [{ id: 1, cc: 'bbc' }, { bb: '123' }],
oldVal: [{ id: 1, cc: 'bb' }, { id: 2, cc: 'bdf' }],
options: { key: 'id' },
});
// => {
// addedLines: [{ bb: '123' }],
// deletedLines: [{ id: 2 }],
// modifiedLines: [{ id: 1, cc: 'bbc' }],
// }
// sortName 模式:追踪未变动但位置改变的行
simpleListDiff({
newVal: [
{ id: 2, cc: 'bdf' },
{ id: 3, bb: '333' },
{ id: 1, cc: 'bb' },
],
oldVal: [
{ id: 1, cc: 'bb' },
{ id: 3, bb: '333' },
{ id: 2, cc: 'bdf' },
],
options: { key: 'id', sortName: 'sortIndex' },
});
// => {
// addedLines: [],
// deletedLines: [],
// modifiedLines: [],
// noChangeLines: [
// { id: 2, sortIndex: 1 },
// { id: 1, sortIndex: 3 },
// ],
// }
// 新增 + 未变动行同时带 sortIndex
simpleListDiff({
newVal: [{ id: 2, cc: 'bbc' }, { id: 1, cc: 'bb' }],
oldVal: [{ id: 1, cc: 'bb' }],
options: { key: 'id', sortName: 'sortIndex' },
});
// => {
// addedLines: [{ id: 2, cc: 'bbc', sortIndex: 1 }],
// deletedLines: [],
// modifiedLines: [],
// noChangeLines: [{ id: 1, sortIndex: 2 }],
// }对任意嵌套对象/数组做递归 diff。结果保留层级结构,每层带 type: 'obj' | 'array'。完全无差异时返回 null。
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
newVal |
新值 | any |
- |
oldVal |
老值 | any |
- |
empty |
旧端存在、新端缺失时的占位 | null | '' | undefined |
null |
行为要点:
undefined统一视作nullDate按valueOf()比较- 嵌套层无差异时不会出现在结果中
import { commonDiff } from 'diff-helper';
commonDiff(
{ a: 1, b: { x: 2, y: 3 }, d: 4 },
{ a: 1, b: { x: 2, y: 9 }, c: 5 }
);
// => { b: { y: 3, type: 'obj' }, d: 4, c: null, type: 'obj' }
commonDiff([1, 2, 3], [1, 9, 3]);
// => { '1': 2, type: 'array' }
commonDiff({ a: 1 }, { a: 1 });
// => null
commonDiff(new Date('2024-01-01'), new Date('2024-01-01'));
// => nullbun install # 装依赖
bun test # 跑测试(78 用例)
bun run typecheck # tsc 类型检查
bun run check # biome 格式化 + lint
bun run build # 产出 dist/(ESM + CJS + d.ts)- 2.0.0
simpleListDiff查找复杂度由 O(n²) 降为 O(n);新增commonDiff通用递归比对;补齐isSimpleObjChange文档;工具链迁移至 Bun + Biome + TypeScript 6;测试用例扩充至 78 个 - 1.0.1 新增
commonDiff通用递归比对;修复commonDiff参数顺序、Date判定、simpleObjDiff深拷贝等问题 - 1.0.0 移除
simpleListDiffWithSort,清理simpleListDiff中不必要的参数 - 0.0.5 为
simpleListDiff和simpleListDiffWithSort的options.getChangedItem提供可用默认项 - 0.0.4 新增
simpleListDiff和simpleListDiffWithSort及测试 - 0.0.3 修复
simpleObjDiffdiffFun返回false的问题,调整参数结构,新增isSimpleObjChange - 0.0.2 基础可用,支持
simpleObjDiff与simpleListDiff
MIT