diff.js - 两个对象对比差异

2023-02-27  本文已影响0人  TedFan

公司项目中有一个需求,要求对比两次填写表单时的差异,表单内容有对象,有数组,因此写了个diff.js,直接贴代码

/**

 * 找到两个相同结构的对象的差异内容,并返回包含所有差异的数组

 * 注意对象内的值只能是简单类型,复杂类型不考虑

 * @param origin 原对象

 * @param current 可能修改过的对象

 * @param arrayKey 数组中需要对比的主键

 */

export function diff(origin, current, arrayKey) {

  let diff = {}

  let log

  for (var key in origin) {

    if (typeof origin[key] === 'object' && typeof current[key] && origin[key] && current[key]) {

      if (origin[key] instanceof Array && current[key] instanceof Array) {

        log = diffArray(origin[key], current[key], arrayKey)

      } else {

        log = diffObject(origin[key], current[key])

      }

      if (Object.keys(log).length > 0) {

        diff[key] = log

      }

    } else if (origin[key] !== current[key]) {

      diff[key] = {

        origin: origin[key],

        current: current[key]

      }

    }

  }

  if (JSON.stringify(diff) == '{}') {

    return null

  } else {

    return diff

  }

}

/**

 * 找到两个相同结构的对象的差异内容,并返回包含所有差异的数组

 * 注意对象内的值只能是简单类型,复杂类型不考虑

 * @param originObj 原对象

 * @param currentObj 可能修改过的对象

 * @returns {{}} 包含所有差异的数组

 */

function diffObject(originObj, currentObj) {

  const resultObj = {};

  // 遍历originObj的键数组,因为originObj和currentObj结构相同,所以不考虑结构上的差异

  Object.keys(originObj).forEach(key => {

    if (originObj[key] !== currentObj[key]) {

      // 将变化过的属性挂载到返回对象中

      resultObj[key] = {

        origin: originObj[key],

        current: currentObj[key]

      }

      // resultObj[key] = currentObj[key];

    }

  });

  if (JSON.stringify(resultObj) == '{}') {

    return false

  } else {

    return resultObj

  }

}

/**

 * 找到两个对象数组的差异,并打印从originList到currentList的所有变化

 * 注意约定id不能修改

 * @param originList 原数组

 * @param currentList 可能修改过的数组

 * @param keyName 子元素主键

 */

function diffArray(originList, currentList, keyName) {

  let logArr = []

  let originListIds = originList.map(v => v[keyName])

  let currentListIds = currentList.map(v => v[keyName])

  originList.forEach((originObj) => {

    let index = currentListIds.indexOf(originObj[keyName])

    if (index >= 0) {

      let tempLog = diffObject(originList[index], currentList[index])

      // 原对象主键在现对象主键中

      if (tempLog) {

        // 如果templog有值,表示修改更新

        let log = {

          id: originObj[keyName],

          operate: 'modify',

          log: tempLog

        }

        logArr.push(log)

      }

    } else {

      // 原对象主键不在现对象主键中,表示原对象已被删除

      let log = {

        id: originObj[keyName],

        operate: 'delete',

        log: originObj

      }

      logArr.push(log)

    }

  })

  currentList.forEach((currentObj) => {

    // 查询新列表中的子元素主键是否存在于旧列表之中

    let index = originListIds.indexOf(currentObj[keyName])

    // 不存在则为新增

    if (index < 0) {

      let log = {

        id: currentObj[keyName],

        operate: 'add',

        log: currentObj

      }

      logArr.push(log)

    }

  })

  return logArr

}

用法

let orgin = { a: '1', b: '2', c: { temp1: 'aaa', temp2: 'bbb' }, d: [{ id: '111', text: 'asd' }, { id: '222', text: 'asdsa' }] }

let current = { a: '1', b: '45', c: { temp1: 'aaa', temp3: 'ccc' }, d: [{ id: '111', text: 'asd' }, { id: '333', text: 'xswedc' }] }

console.log(diff(orgin, current, 'id'))

上一篇下一篇

猜你喜欢

热点阅读