如何在一个对象中合并对象数组,包括内部对象 - JavaScript?

时间:2018-05-12 03:56:21

标签: javascript arrays object ecmascript-6

假设我有以下对象数组:

var list = [
  { a: 1, 
    b: { c: 'x', k: []}
  },
  { a: 1,
    b: {c: 'x', d: 8}
  }
];

我希望它们合并为一个“通用”对象,对于这个例子,它将是:

{a: 1, b: {c: 'x', d:'8', k[]}}

如您所见,所有嵌套对象也会合并。但我无法获得它。如果我使用Object.assign,它会创建新的嵌套对象,如果它们不同,那就是重复它们:

var res = Object.assign({}, ...list);
// res: {
    a: 1, 
    b: {c: 'x', k: []},
    b: {c: 'x', d: 8}
}

3 个答案:

答案 0 :(得分:2)

您可以使用reduce方法尝试以下操作:

var list = [{
  a: 1,
  b: {
    a: 4,
    k: 3
  }
}, {
  a: 1,
  s: 11,
  b: {
    ab: 4,
    d: 8
  }
}]

var result = list.reduce(function(acc, item) {
  var obj = { ...item
  }
  Object.keys(obj).forEach(function(item) {
    if (acc[item]) { //if a property with the the key, 'item' already exists, then append to that
      Object.assign(acc[item], obj[item]);
    } else { // else add the key-value pair to the accumulator object.
      acc[item] = obj[item];
    }
  })
  return acc;
}, {})

console.log(result);

答案 1 :(得分:1)

Deep merging自己做起来并不简单,该博客使用deep merge

如果你没有webpack或nodejs,你可以像这样使用deepmerge:



// see https://github.com/facebook/react/blob/b5ac963fb791d1298e7f396236383bc955f916c1/src/isomorphic/classic/element/ReactElement.js#L21-L25
var canUseSymbol = typeof Symbol === 'function' && Symbol.for
var REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for('react.element') : 0xeac7

function isReactElement(value) {
	return value.$$typeof === REACT_ELEMENT_TYPE
}

function isNonNullObject(value) {
	return !!value && typeof value === 'object'
}

function isSpecial(value) {
	var stringValue = Object.prototype.toString.call(value)

	return stringValue === '[object RegExp]'
		|| stringValue === '[object Date]'
		|| isReactElement(value)
}

function defaultIsMergeableObject(value) {
	return isNonNullObject(value)
		&& !isSpecial(value)
}



function emptyTarget(val) {
	return Array.isArray(val) ? [] : {}
}

function cloneUnlessOtherwiseSpecified(value, options) {
	return (options.clone !== false && options.isMergeableObject(value))
		? deepmerge(emptyTarget(value), value, options)
		: value
}

function defaultArrayMerge(target, source, options) {
	return target.concat(source).map(function(element) {
		return cloneUnlessOtherwiseSpecified(element, options)
	})
}

function mergeObject(target, source, options) {
	var destination = {}
	if (options.isMergeableObject(target)) {
		Object.keys(target).forEach(function(key) {
			destination[key] = cloneUnlessOtherwiseSpecified(target[key], options)
		})
	}
	Object.keys(source).forEach(function(key) {
		if (!options.isMergeableObject(source[key]) || !target[key]) {
			destination[key] = cloneUnlessOtherwiseSpecified(source[key], options)
		} else {
			destination[key] = deepmerge(target[key], source[key], options)
		}
	})
	return destination
}

function deepmerge(target, source, options) {
	options = options || {}
	options.arrayMerge = options.arrayMerge || defaultArrayMerge
	options.isMergeableObject = options.isMergeableObject || defaultIsMergeableObject

	var sourceIsArray = Array.isArray(source)
	var targetIsArray = Array.isArray(target)
	var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray

	if (!sourceAndTargetTypesMatch) {
		return cloneUnlessOtherwiseSpecified(source, options)
	} else if (sourceIsArray) {
		return options.arrayMerge(target, source, options)
	} else {
		return mergeObject(target, source, options)
	}
}

deepmerge.all = function deepmergeAll(array, options) {
	if (!Array.isArray(array)) {
		throw new Error('first argument should be an array')
	}

	return array.reduce(function(prev, next) {
		return deepmerge(prev, next, options)
	}, {})
}
var list = [{
  a: 1,
  b: {
    c: 'x',
    //merging 1,2 and 1,3 results in [1,2,1,3] you can change that in defaultArrayMerge
    k: [1,2]
  }
},
{
  a: 1,
  b: {
    c: 'x',
    k: [1,3],
    d: 8
  }
}];

console.log(
  deepmerge.all(list)
)




答案 2 :(得分:0)

您可以使用reduce方法。从原始列表中删除第一个元素,该对象将是基本方法。



var list = [{
    a: 1,
    b: {
      c: 'x',
      k: []
    }
  },
  {
    a: 1,
    b: {
      c: 'x',
      d: 8
    }
  }
];
// Remove the first element from the array. The first element will be
// the base object
// slice will return a new array without the first object
// apply reduce on this list
let _temp = list.slice(1);
let x = _temp.reduce(function(acc,curr,currIndex){
    for(let keys in curr){
      // checking if the base object have the same key as of current object
      if(acc.hasOwnProperty(keys)){
          // if base object and current object has the key then 
         // check if the type is an object
         if(typeof curr[keys] ==='object'){
          // now get the key from both the object 
          // & check which one is missong. Add that key and value to the 
          // base object
           let keysFromACC = Object.keys(acc[keys]);
          let keysFromCURR = Object.keys(curr[keys]);
          keysFromCURR.forEach(function(item){
           if(keysFromACC.indexOf(item) ===-1){
              acc[keys][item] = curr[keys][item]
           }
          })
         }
      }
      else{
       // if the base object does not have key which current object
       // has then add the key to base object
       acc[keys]= curr[keys]
      }
    
    }
    return acc;

},list[0]);


console.log(x)