如何实现两个同键JS对象对比,返回formData中与initialValues值不同的键值对?
变更值对比实现方案
基础浅比较(适配当前示例场景)
你当前的示例里所有字段值都是字符串这类基本类型,不需要复杂逻辑,直接做严格相等对比就行:
实现思路:
- 以参照对象
initialValues的键集合作为遍历范围,避免纳入formData里独有的无参照字段 - 逐个对比同名字段两边的值,只要不相等,就把
formData里对应的键值对收集到最终结果里
可直接运行的示例代码:
const getChangedValues = (initialValues, formData) => { return Object.keys(initialValues).reduce((changed, key) => { // 同键值不匹配就收集formData的对应值 if (formData[key] !== initialValues[key]) { changed[key] = formData[key] } return changed }, {}) } // 对应你的测试用例 const initialValues = { name: "Robert Terrell", email: "billy@gmail.com" } const formData = { name: 'New Name', email: 'new email' } console.log(getChangedValues(initialValues, formData)) // 输出结果:{ name: 'New Name', email: 'new email' }
支持深度对比的增强实现
如果你的表单字段里有嵌套对象、数组、日期这类引用类型的值,直接用!==对比会失效——因为两个内容完全一样的对象,只要引用地址不同就会被判定为不相等。这个时候就需要递归逐层对比内容:
实现逻辑:
- 基本类型 的值直接做严格相等对比
- 特殊引用类型(日期、正则)提取实际内容做对比
- 普通对象、数组类型,递归遍历内部键值,直到对比到最内层的基本类型值
- 只有递归判定内容真的有差异,才把对应字段纳入结果集合
简化版深度对比实现代码:
// 深度相等判断工具 const isDeepEqual = (valA, valB) => { // 同值/同引用直接判定相等 if (Object.is(valA, valB)) return true // 任意一侧不是引用类型、或者为null,直接判定不等 if (typeof valA !== 'object' || valA === null || typeof valB !== 'object' || valB === null) { return false } // 处理日期类型,对比时间戳 if (valA instanceof Date && valB instanceof Date) { return valA.getTime() === valB.getTime() } // 处理正则类型,对比序列化后的规则内容 if (valA instanceof RegExp && valB instanceof RegExp) { return valA.toString() === valB.toString() } // 两侧原型不一致(比如一侧是数组一侧是普通对象)直接判定不等 if (Object.getPrototypeOf(valA) !== Object.getPrototypeOf(valB)) return false const keysA = Object.keys(valA) const keysB = Object.keys(valB) // 键数量不一致直接判定不等 if (keysA.length !== keysB.length) return false // 递归对比每一个嵌套键值 return keysA.every(key => isDeepEqual(valA[key], valB[key])) } // 收集深度变更值的方法 const getDeepChangedValues = (initialValues, formData) => { return Object.keys(initialValues).reduce((changed, key) => { // 用深度相等判断替换基础对比的严格不等 if (!isDeepEqual(formData[key], initialValues[key])) { changed[key] = formData[key] } return changed }, {}) }
实际使用注意点
- 遍历范围必须以
initialValues的键为基准,不要遍历formData的键,否则会把formData里新增的无参照字段错误判定为变更值 - 优先根据业务场景选择对比方案:全基本类型字段的表单直接用浅比较,性能更高,不要一开始就上递归逻辑
- 如果业务里有循环引用的对象,需要额外加一层遍历过的对象缓存,避免递归进入死循环
内容的提问来源于stack exchange,提问作者Rob Terrell
相关产品推荐
相关产品推荐

