我看过几篇关于将两个对象合并在一起的文章,但是大多数文章都是关于合并包含不包含嵌套元素的对象的对象的。当我实施建议的解决方案之一时,一个对象的属性将被覆盖。
const Gnome = () => {
return {
ExpRate: .20,
Abilities: {
PickDoors: 1,
},
Buffs: {
NightSight: 65,
MagicRes: 5,
},
... Additional data and behaviors
};
}
const Thief = () {
return {
ExpRate: 2.10,
Abilities: {
Thievery: 1,
PickDoors: 1,
},
Buffs: {},
// ... Additional data and behavors
};
}
我一直试图将两个对象合并为:
{
ExpRate: 2.30,
Abilities: {
PickDoors: 2,
Thievery: 1
},
Buffs: {
NightSight: 65,
MagicRes: 5,
},
// ... Additional data and behavors from both objects
};
但是,使用Object.assign将覆盖现有键中的值,从而丢失数据。 IE:
const myGnome = Gnome();
const myThief = Thief();
const myPlayer = Object.assign({}, myGnome, myThief);
我尝试了人们发布的一些建议的合并方法,但是它们似乎都具有与Object.assign()相同的行为; 任何建议,将不胜感激。如果这实际上是重复的帖子,我将喜欢它的链接。
谢谢。
答案 0 :(得分:2)
您可以迭代条目并检查是否找到对象,然后再次为嵌套对象调用该函数。如果找到数字,请添加此值。
function merge(a, b) {
function mergeTo(source, target) {
Object.entries(source).forEach(([k, v]) => {
if (Array.isArray(v)) {
target[k] = target[k] || [];
target[k].push(...v);
return;
}
if (v && typeof v === 'object') {
mergeTo(v, target[k] = target[k] || {});
return;
}
if (typeof v === 'number') {
target[k] = (target[k] || 0) + v;
return;
}
if (!(k in target)) {
target[k] = v;
return;
}
target[k] = Array.isArray(target[k])
? [...target[k], v]
: [target[k], v];
});
}
var object = {};
mergeTo(a, object);
mergeTo(b, object);
return object;
}
console.log(merge(
{ ExpRate: .20, Abilities: { PickDoors: 1 }, Buffs: { NightSight: 65, MagicRes: 5 }, array: [1, 2], v: 'a' },
{ ExpRate: 2.10, Abilities: { Thievery: 1, PickDoors: 1 }, Buffs: {}, array: [3, 4], v: 'b', f: true }
));
.as-console-wrapper { max-height: 100% !important; top: 0; }
答案 1 :(得分:1)
您可以使用递归来实现。下面是示例
const Gnome = () => {
return ({
ExpRate: .20,
Abilities: {
PickDoors: 1,
},
Buffs: {
NightSight: 65,
MagicRes: 5,
}
});
}
const Thief = () => {
return ({
ExpRate: 2.10,
Abilities: {
Thievery: 1,
PickDoors: 1,
},
Buffs:{}
});
}
let thief = Thief();
let gnone = Gnome();
function merge(obj1,obj2){
let keys1 = Object.keys(obj1);
let keys2 = Object.keys(obj2);
let objToReturn = Object.assign({},obj1,obj2);
let sameKeys = [... new Set(keys1.filter(key => keys2.includes(key)).concat(keys2.filter(key => keys1.includes(key))))]
sameKeys.forEach(key => {
if(typeof obj1[key] === "object") objToReturn[key] = merge(obj1[key],obj2[key]);
else objToReturn[key] = obj2[key] + obj1[key];
})
return objToReturn;
}
console.log(merge(thief,gnone));
答案 2 :(得分:0)
感谢您的答复。我会给你建议的。我能够按照建议编写一个函数:
function isObject(item) {
return (item && typeof item === 'object' && !Array.isArray(item));
}
function mergeDeep(target, source) {
let output = Object.assign({}, target);
if (isObject(target) && isObject(source)) {
Object.keys(source).forEach(key => {
if (isObject(source[key])) {
if (!(key in target))
Object.assign(output, { [key]: source[key] });
else
output[key] = mergeDeep(target[key], source[key]);
} else {
if(typeof target[key] === 'number' && typeof source[key] === 'number'){
source[key] += target[key];
}
Object.assign(output, { [key]: source[key] });
}
});
}
return output;
}
console.log(
mergeDeep(
{ExpRate: .20, Abilities: {PickDoors: 1}, Buffs: {NightSight: 65, MagicRes: 5}},
{ExpRate: 2.10, Abilities: {Thievery: 1, PickDoors: 1}}
));
由于我担心上述方法可能会有些混乱,并在将来导致问题,因此我将给出其他建议。