Files
wvp-platform/web/src/utils/diff.js

77 lines
2.4 KiB
JavaScript

// utils/diff.js
// 返回 newObj 相对于 oldObj 的变化部分(新增/修改)。
// 可选 includeRemoved=true 时把被删除字段以 removedValue 标记返回。
// 使用示例: diff(oldObj, newObj) 或 diff(oldObj, newObj, { includeRemoved: true })
export function diff(oldObj, newObj, options = {}) {
const { includeRemoved = false, removedValue = null, comparator } = options
function isObject(v) {
return v && typeof v === 'object' && !Array.isArray(v) && !(v instanceof Date)
}
function isDate(v) {
return v instanceof Date
}
function equal(a, b) {
if (typeof comparator === 'function') return comparator(a, b)
if (isDate(a) && isDate(b)) return a.getTime() === b.getTime()
if (Array.isArray(a) && Array.isArray(b)) {
if (a.length !== b.length) return false
for (let i = 0; i < a.length; i++) if (!equal(a[i], b[i])) return false
return true
}
if (isObject(a) && isObject(b)) {
const aKeys = Object.keys(a)
const bKeys = Object.keys(b)
if (aKeys.length !== bKeys.length) return false
for (const k of aKeys) {
if (!Object.prototype.hasOwnProperty.call(b, k) || !equal(a[k], b[k])) return false
}
return true
}
return a === b
}
function inner(o, n) {
// Normalize undefined -> empty object for easier handling in object branch.
const oIsObj = isObject(o)
const nIsObj = isObject(n)
if (equal(o, n)) return undefined
if (oIsObj && nIsObj) {
const result = {}
const keys = new Set([...Object.keys(o || {}), ...Object.keys(n || {})])
for (const k of keys) {
console.log(k)
const hasO = Object.prototype.hasOwnProperty.call(o || {}, k)
const hasN = Object.prototype.hasOwnProperty.call(n || {}, k)
if (hasN) {
const sub = inner(hasO ? o[k] : undefined, n[k])
if (sub !== undefined) result[k] = sub
} else if (hasO && includeRemoved) {
// key existed before but removed now
result[k] = removedValue
}
}
return Object.keys(result).length ? result : undefined
}
if (Array.isArray(o) && Array.isArray(n)) {
return equal(o, n) ? undefined : n
}
if (isDate(n)) return n
// Different primitive or type change -> return new value
return n
}
const res = inner(oldObj ?? {}, newObj ?? {})
return res === undefined ? {} : res
}
export default diff