JavaScript比对不同键名对象做值同步有没有更易读的实现方案?
JavaScript 比对异构对象实现数据同步的优化方案
针对你需要比对键名不同、结构不同、类型不同的两个对象生成同步数据的需求,最易维护的实现思路是把字段映射规则和业务执行逻辑完全分离,所有字段的取值、比对、转换规则统一管理,后续增删改字段都不需要改动核心逻辑。
完整实现代码如下:
// 1. 单独抽离字段映射配置,所有规则统一管理,后续增删改字段只需要改这里 const fieldMapping = [ { targetKey: 'id', // 定义从待同步对象取值的方法 getSyncVal: (syncObj) => syncObj.meta_data.find(x => x.key === 'productid').value, // 定义从主数据对象取值的方法 getMainVal: (mainObj) => mainObj.id, // 可选:值转换方法,返回要同步的最终值 transform: (syncVal, mainVal) => mainVal, // 可选:自定义比对逻辑,返回true表示值一致不需要同步 isEqual: (syncVal, mainVal) => String(syncVal) === String(mainVal) }, { targetKey: 'name', getSyncVal: (syncObj) => syncObj.name, getMainVal: (mainObj) => mainObj.name.en, isEqual: (syncVal, mainVal) => syncVal.toLowerCase() === mainVal.toLowerCase() }, { targetKey: 'price', getSyncVal: (syncObj) => Number(syncObj.price), getMainVal: (mainObj) => mainObj.price, // WooCommerce要求价格为字符串格式,转换后返回 transform: (syncVal, mainVal) => String(mainVal), isEqual: (syncVal, mainVal) => syncVal === mainVal }, { targetKey: 'status', getSyncVal: (syncObj) => syncObj.status, getMainVal: (mainObj) => mainObj.status, transform: (syncVal, mainVal) => mainVal === 'ACTIVE' ? 'publish' : 'draft', isEqual: (syncVal, mainVal) => { const convertedStatus = mainVal === 'ACTIVE' ? 'publish' : 'draft' return syncVal === convertedStatus } }, { targetKey: 'stock_quantity', getSyncVal: (syncObj) => syncObj.stock_quantity, getMainVal: (mainObj) => mainObj.quantity_in_stock, transform: (syncVal, mainVal) => mainVal, isEqual: (syncVal, mainVal) => syncVal === mainVal }, { targetKey: 'categories', getSyncVal: (syncObj) => syncObj.categories, getMainVal: (mainObj) => mainObj.group_id, transform: (syncVal, mainVal) => { // 对应分类ID映射逻辑 const categoryMap = categories.find(item => item.syncToId === mainVal) return categoryMap ? categoryMap.id : mainVal }, isEqual: (syncVal, mainVal) => { const categoryMap = categories.find(item => item.syncToId === mainVal) const convertedVal = categoryMap ? categoryMap.id : mainVal return syncVal === convertedVal } } ] // 2. 通用的差异生成逻辑,不需要随着字段修改改动 function generateSyncObj(objectToSync, mainObject, mapping) { const syncResult = {} for (const field of mapping) { const syncVal = field.getSyncVal(objectToSync) const mainVal = field.getMainVal(mainObject) // 没有自定义比对逻辑就用默认全等判断 const isSame = field.isEqual ? field.isEqual(syncVal, mainVal) : syncVal === mainVal if (!isSame) { // 有转换逻辑就用转换后的值,否则直接用主数据的值 syncResult[field.targetKey] = field.transform ? field.transform(syncVal, mainVal) : mainVal } } return syncResult } // 3. 调用示例 const categories = [{ id: 21, syncToId: 2 }] const objectToSync = { id: 44, status: 'publish', name: 'test product', price: '1.99000000', stock_quantity: 0, categories: 21, meta_data: [{ key: 'productid', value: '226' }, { key: 'irrelevant data', value: 'meow' }] } const mainObject = { id: 226, status: 'ACTIVE', name: { en: 'Test Product Updated' }, price: 2.99, quantity_in_stock: 5, group_id: 2, } const toUpdateObj = generateSyncObj(objectToSync, mainObject, fieldMapping) console.log(toUpdateObj) // 输出结果:{ name: 'Test Product Updated', price: '2.99', stock_quantity: 5 }
方案优势
- 可维护性高:所有字段的映射、转换、比对规则都集中在
fieldMapping配置里,后续新增同步字段只需要加一条配置,不需要改核心逻辑 - 可读性强:逻辑分层清晰,新手也能快速看懂每个字段的处理规则,排查问题直接找对应字段的配置即可
- 复用性好:通用比对逻辑可以复用在所有产品的比对场景,不需要重复写判断代码
内容的提问来源于stack exchange,提问作者yayza
相关产品推荐
相关产品推荐

