【问题标题】:How to merge two objects, overriding null values?如何合并两个对象,覆盖空值?
【发布时间】:2019-10-04 21:17:05
【问题描述】:

我想合并两个相似但不相同的对象,并在其中一个对象中覆盖空值(如果存在)。例如,我有这两个对象:

const obj1 = {
    a: 1,
    b: '',
    c: [],
    d: null
}

const obj2 = {
    a: 2,
    b: null,
    d: 1
}

而合并的效果应该是:

const objMerged = {
    a: 2,
    b: '',
    c: [],
    d: 1
}

换句话说,合并对象中最重要的数据源是obj2,但它缺少obj1的一些属性,因此需要复制它们,并且obj2的一些值是null所以它们也应该取自obj1

编辑 我试过了:

_.extend({}, obj1, obj2) 

Object.assign({}, obj1, obj2)

【问题讨论】:

  • 问之前有没有试过?
  • 是的,Object.assign 和 lodash 扩展函数。
  • 您能否在问题中包含您的尝试
  • Object.assign({}, obj1, obj2);
  • 请用您的两次尝试编辑问题

标签: javascript merge lodash


【解决方案1】:

如果您只对这两个对象的第一级感兴趣,您可以这样做:

const obj1 = {
  a: 1,
  b: '',
  c: [],
  d: null
}

const obj2 = {
  a: 2,
  b: null,
  d: 1
}

const merged = Object.keys(obj1).concat(Object.keys(obj2)) // create an array that contains the keys of the two objects.
  .filter((k, i, arr) => arr.indexOf(k) === i) // remove duplicate keys
  .reduce((a, c) => {
    a[c] = obj1[c] !== null ? obj1[c] : obj2[c];
    return a;
  }, {});

console.log(merged);

此示例仅检查 null 值,您应该扩展它以检查其他值,例如 undefined、空字符串等。

【讨论】:

    【解决方案2】:

    您使用Object.assign 做得很好,只需删除您之前不想要的内容

    Object.keys(obj1).forEach( k => {
        if ( obj1[k] //write the condition you want
            delete obj1[k]
    });
    

    【讨论】:

      【解决方案3】:

      您可以使用_.mergeWith(),并且在合并回调中,如果不是null,则只取第二个值:

      const obj1 = { a: 1, b: '', c: [], d: null }
      const obj2 = { a: 2, b: null, d: 1 }
      
      const result = _.mergeWith({}, obj1, obj2, (o, s) => _.isNull(s) ? o : s)
      
      console.log(result)
      <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>

      【讨论】:

        【解决方案4】:

        create()omitBy() 使用 Lodash

        const obj1 = {"a":1,"b":"","c":[],"d":null}
        
        const obj2 = {"a":2,"b":null,"d":1}
        
        const objMerged = _.create(
          _.omitBy(obj1, _.isNull),
          _.omitBy(obj2, _.isNull)
        )
        
        console.log(objMerged)
        <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

        【讨论】:

          【解决方案5】:

          这是一个纯 JS 的解决方案:

          遍历第一个对象以替换第二个对象的值,然后添加第二个对象的附加值。

          const obj1 = {
              a: 1,
              b: '',
              c: [],
              d: null
          }
          
          const obj2 = {
              a: 2,
              b: null,
              d: 1
          }
          
          function mergeObjs(obj1, obj2){
            const merged = {}
            keys1 = Object.keys(obj1);
            keys1.forEach(k1 => {
               merged[k1] = obj2[k1] || obj1[k1]; // replace values from 2nd object, if any
            })
            Object.keys(obj2).forEach(k2 => {
               if (!keys1.includes(k2)) merged[k2] = obj[k2]; // add additional properties from second object, if any
            })
            return merged
          }
          
          
          console.log(mergeObjs(obj1, obj2))

          【讨论】:

          • merged[k2] = obj[k2] 需要合并[k2] = obj2[k2]
          【解决方案6】:
          var objMerged  = {};
          for (var kobj1 in obj1) {
              for (var kobj2 in obj2) {
                  if (obj1[kobj1] == null && obj2[kobj1] != null)
                      objMerged[kobj1] = obj2[kobj1];
                  else if (obj2[kobj2] == null && obj1[kobj2] != null)
                      objMerged[kobj2] = obj1[kobj2];
          
              }
          }
          

          //打印obj合并显示

          【讨论】:

            【解决方案7】:

            您还可以与ES6 destructuring 和lodash _.omitBy 混合搭配:

            const obj1 = { a: 1, b: '', c: [], d: null }
            const obj2 = { a: 2, b: null, d: 1 }
            
            const result = {..._.omitBy(obj1, _.isNull), ..._.omitBy(obj2, _.isNull)}
            
            console.log(result)
            <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

            你也可以像这样使用 ES6:

            const obj1 = { a: 1, b: '', c: [], d: null }
            const obj2 = { a: 2, b: null, d: 1 }
            
            let omitNull = obj => {
              Object.keys(obj).filter(k => obj[k] === null).forEach(k => delete(obj[k]))
              return obj
            }
            
            const result = { ...omitNull(obj1), ...omitNull(obj2) }
            
            console.log(result)

            【讨论】:

              【解决方案8】:

              要添加到这个好答案列表,这里有一个适用于嵌套结构的递归解决方案。

              本示例将dst对象的通用属性合并到src对象的所有嵌套级别,不通用的属性保持不变。

              const merge = (dst, src) => {
                Object.keys(src).forEach((key) => {
                  if (!dst[key]) {
                    dst[key] = src[key];
                  } else if (typeof src[key] === 'object' && src[key] !== null && typeof dst[key] === 'object' && dst[key] !== null) {
                    merge(dst[key], src[key]);
                  }
                });
              },
              
              /* Usage: */
              
              src = {
                prop1: '1',
                prop2: {
                  val: 2,
                }
              },
              dst = {
                prop1: null,
                prop2: {
                  val: null,
                },
                prop3: null,
              };
              
              merge(dst, src);
              console.log(dst);

              【讨论】:

              • 很好的答案。我真的很喜欢这个解决方案!
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2014-01-02
              • 1970-01-01
              • 2018-05-13
              • 2018-04-22
              • 2018-11-10
              • 1970-01-01
              • 2019-06-19
              相关资源
              最近更新 更多