如何通过键深度合并两个对象值

IT技术 javascript jquery
2021-01-28 02:48:14

尝试查看是否有任何 javascript 库功能可以合并两个 json 对象的特定键的值

var x ={ "student-marks":{'math':1,'physics':5} };
var y ={ "student-marks":{'chemistry':3,'history':2} };

使用 $.extend 和 $.merge 给出以下结果

$.extend({},x,y)  leads to  { "student-marks":{'chemistry':3,'history':2} }

$.merge(x,y) leads to { "student-marks":{'math':1,'physics':2} }

我要找的是 ‍{ "student-marks":{'math':1,'physics':5, 'chemistry':3,'history':2} }‍

5个回答

你想要一个深度的延伸

$.extend(true, {}, x, y);

请参阅jQuery.extend([ deep ], target , object1 [, objectN ])的文档

lodash 或下划线的类似解决方案是什么?我有几乎相同的问题,但不使用 jQuery,可能更喜欢 _.merge 的 lodash 实现?这是我的问题:stackoverflow.com/questions/23186187/...
2021-03-26 02:48:14

不依赖 jQuery 的简单 javascript 函数将帮助您合并两个具有嵌套对象的 JSON 对象。

function mergeJSON(source1,source2){
    /*
     * Properties from the Souce1 object will be copied to Source2 Object.
     * Note: This method will return a new merged object, Source1 and Source2 original values will not be replaced.
     * */
    var mergedJSON = Object.create(source2);// Copying Source2 to a new Object

    for (var attrname in source1) {
        if(mergedJSON.hasOwnProperty(attrname)) {
          if ( source1[attrname]!=null && source1[attrname].constructor==Object ) {
              /*
               * Recursive call if the property is an object,
               * Iterate the object and set all properties of the inner object.
              */
              mergedJSON[attrname] = mergeJSON(source1[attrname], mergedJSON[attrname]);
          } 

        } else {//else copy the property from source1
            mergedJSON[attrname] = source1[attrname];

        }
      }

      return mergedJSON;
}
还在等你@andrewlorien
2021-03-26 02:48:14
此脚本适用于简单对象。为了使它与嵌套对象一起工作,我不得不稍微更改脚本。要使其与对象内的数组一起使用,需要另一个代码块。当我做对了,我会把它贴在这里。
2021-04-09 02:48:14
此解决方案在 NodeJS 中不起作用。必须安装npmjs.com/package/extend
2021-04-11 02:48:14

ES2018 的新扩展运算符提供了一些很好的方法来做到这一点:

function combine(...list){
  return list.reduce(
     (a,b)=>{
       return {...a,...b}
     }
  )
}

// work as expected with simple objects
console.log(
  combine(
    {x:3,z:1},
    {x:4,m:4},
    {a:1},
    {b:2}
));

// is not a good recursive solution
console.log(
  combine(
    {x:3,z:1,child:{c:1}},
    {x:4,m:4,child:{d:3}},
    {a:1},
    {b:2}
));

这是我能得到的最好的递归解决方案

function combine_recursive(...list) {    
    return list.reduce(
        (a,b) => {
            // for non objects return b if exists or a
            if ( ! ( a instanceof Object ) || ! ( b instanceof Object ) ) {
                return b !== undefined ? b : a;
            }
            // for objects, get the keys and combine them
            const keys = Object.keys(a).concat(Object.keys(b));
            return keys.map(
                key => { 
                    return  {[key]: combine_recursive(a[key],b[key])}
                }
            ).reduce(
                (x,y) => {
                    return {...x,...y}
                }
            );
        }
    )
}
   
// testing recursive and the priority
console.log(
  combine_recursive(
    {x:3,z:1,child:{c:1,k:1}},
    {x:4,m:4,child:{d:3,k:2}},
    {a:1},
    {b:2}
));
 
// using the example of the question
var x ={ "student-marks":{'math':1,'physics':5} };
var y ={ "student-marks":{'chemistry':3,'history':2} };
console.log( combine_recursive(x,y) );

    https://gist.github.com/samad-aghaei/7250ffb74ed80732debb1cbb14d2bfb0

<pre>
/**
This script can merge two multi dimensional associative array/objects in javascript by comparing given object with its reference and 
will remove additional given keys, adding missed parameteres and also validating values without overhead. Also it will return the default values if no input presented with re-usable reference!
Tested on IE8 and greater.
**/
var module = (function(){
    //To make our reference variable onchangable, have to put it into a function which is fster and more efficient than "JSON.parse(JSON.stringify(VARIABLE))"
    var _defs = function(){
            return {
                   //string, number and boolean are actually regex based validation keys on input values.
                a: ["string", 'Defaul value for "a"'],
                b: ["number", 300],
                c: ["boolean", true],
                d: {
                  da: ["boolean", true],
                  db: ["string", 'Defaul value for "db"'],
                  dc: {
                    dca: ["number", 200],
                    dcb: ["string", 'Default value for "dcb"'],
                    dcc: ["number", 500],
                    dcd: ["boolean", true]
                  },
                  dce: ["string", 'Default value for "dce"'],
                },
                e: ["number", 200],
                f: ["boolean", 0],
                g: ["", 'This is an internal extra parameter']
            }
        }

        var _validation = {
                number: function (defaultValue, userValue) {
                  if(/^[0-9]+$/.test(userValue)) //Only numbers allowed
                    return userValue;
                  else return defaultValue;
                },
                string: function (defaultValue, userValue) {
                  if(/^[a-zA-Z\s]*$/.test(userValue)) //Only A to Z case insentitive with space aloowed.
                    return userValue;
                  else return defaultValue;
                },
                boolean: function (defaultValue, userValue) {
                  if(typeof userValue === 'boolean') //True or False or 0 ,1
                    return userValue;
                  else return defaultValue;
                }
        }

        var _uniqueMerge = function(opts, _ref){
                for(var key in _ref)
                    if (_ref && _ref[key] && _ref[key].constructor && _ref[key].constructor === Object)
                      _ref[key] = _uniqueMerge((opts ? opts[key] : null ), _ref[key] );
                    else if(opts && opts.hasOwnProperty(key))
                      _ref[key] = _validation[_ref[key][0]](_ref[key][1], opts[key]); //or without validation on user enties => ref[key] = obj[key]
                    else _ref[key] = _ref[key][1];
                return _ref;
        }
        var _get = function(inputs){
            return _uniqueMerge(inputs, _defs());
        }
        return {
            options: function(){
            return _get(arguments[0] || null); // for more safety and control on number of input variables! used --> ( arguments[0] || null )
            }
        }
})();


//How to use it:    

input_one = { 
    a : "Hello World", 
  //b : ["number", 400], //User missed this parameter
    c: "Hi",
    d : {
        da : false,
        db : "Hellow! World", // ! is not allowed
        dc : {
            dca : 10,
            dcb : "My String",
            dcc: "3thString",
            dcd : false
      },
      dce: "ANOTHER STRING",
    },
    e: 40,
    f: true,
    z: 'x'
};
console.log( JSON.stringify( module.options(input_one), null ,2 ) );
//Output:
/*
{
  "a": "Hello World",
  "b": 300,
  "c": true,
  "d": {
    "da": false,
    "db": "Defaul value for \"db\"",
    "dc": {
      "dca": 10,
      "dcb": "My String",
      "dcc": 500,
      "dcd": false
    },
    "dce": "ANOTHER STRING"
  },
  "e": 40,
  "f": true,
  "g": "This is an internal extra parameter"
}
*/
input_two = { 
    a : 32,
  //b : ["number", 400], //User missed this parameter
    c: "Hi",
    d : {
        da : false,
        db : "HelloWorld",
        dc : {
            dca : 10,
            dcb : "My String",
            dcd : false
      },
      dce: 73,
    }
};
console.log( JSON.stringify( module.options(input_two), null ,2 ) );
//output
/*
{
  "a": "Defaul value for \"a\"",
  "b": 300,
  "c": true,
  "d": {
    "da": false,
    "db": "HelloWorld",
    "dc": {
      "dca": 10,
      "dcb": "My String",
      "dcc": 500,
      "dcd": false
    },
    "dce": "Default value for \"dce\""
  },
  "e": 200,
  "f": 0,
  "g": "This is an internal extra parameter"
}
*/
//Empty input will return the default values!
console.log( JSON.stringify( module.options(), null ,2 ) );     
//Output
/*  
{
  "a": "Defaul value for \"a\"",
  "b": 300,
  "c": true,
  "d": {
    "da": true,
    "db": "Defaul value for \"db\"",
    "dc": {
      "dca": 200,
      "dcb": "Default value for \"dcb\"",
      "dcc": 500,
      "dcd": true
    },
    "dce": "Default value for \"dce\""
  },
  "e": 200,
  "f": 0,
  "g": "This is an internal extra parameter"
}
*/</pre>

不那么冗长。

answer = { "student-marks": Object.assign(x['student-marks'], y['student-marks']) }
  • 警告这对 x 有副作用。