两个对象。assign和Object spread只做浅合并。
这个问题的一个例子:
// No object nesting
const x = { a: 1 }
const y = { b: 1 }
const z = { ...x, ...y } // { a: 1, b: 1 }
输出是您所期望的。然而,如果我尝试这样做:
// Object nesting
const x = { a: { a: 1 } }
const y = { a: { b: 1 } }
const z = { ...x, ...y } // { a: { b: 1 } }
而不是
{ a: { a: 1, b: 1 } }
你得到
{ a: { b: 1 } }
X被完全覆盖,因为扩展语法只覆盖了一层。这与Object.assign()相同。
有办法做到这一点吗?
我把这里所有的答案都看了一遍,然后拼凑出了一个我自己的答案。现有的大多数答案都不是我想要的方式。
这对于2021年来说是相当可怕的,所以任何改善的建议,我都洗耳恭听!
这是在Typescript中
type Props = Record<string, any>
export const deepMerge = (target: Props, ...sources: Props[]): Props => {
if (!sources.length) {
return target
}
Object.entries(sources.shift() ?? []).forEach(([key, value]) => {
if (!target[key]) {
Object.assign(target, { [key]: {} })
}
if (
value.constructor === Object ||
(value.constructor === Array && value.find(v => v.constructor === Object))
) {
deepMerge(target[key], value)
} else if (value.constructor === Array) {
Object.assign(target, {
[key]: value.find(v => v.constructor === Array)
? target[key].concat(value)
: [...new Set([...target[key], ...value])],
})
} else {
Object.assign(target, { [key]: value })
}
})
return target
}
平面数组使用[…]删除重复值。新的(…)]。
嵌套数组使用concat连接。
这里是@Salakar的答案的一个不可变(不修改输入)版本。如果你在做函数式编程,这很有用。
export function isObject(item) {
return (item && typeof item === 'object' && !Array.isArray(item));
}
export default 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 {
Object.assign(output, { [key]: source[key] });
}
});
}
return output;
}
简单递归解
使用对象。条目,遍历其中一个对象。如果条目不存在,则添加该条目;如果条目是对象,则递归。
常量x = {a: {a: 1}}
Const y = {a: {b: 1}}
JSON.parse(JSON.stringify(y))
const mergeIntoZ = (firstObj, secondObj) => {
Object.entries (firstObj)
.forEach(([key, value]) => {
if (secondObj[key] === undefined) {
secondObj[key] = value
} else if (typeof value === 'object') {
mergeIntoZ (firstObj(关键),secondObj[主要])
}
})
}
mergeIntoZ (x, z)
console.log (z)
许多答案使用数十行代码,或者需要向项目添加一个新库,但如果您使用递归,这只是4行代码。
函数合并(当前,更新){
for (Object.keys(updates)的key) {
if (!current. hasownproperty (key) || typeof updates[key] !== 'object') current[key] = updates[key];
Else merge(current[key], updates[key]);
}
返回当前;
}
console.log(合并({答:{:1}},{:{b: 1}}));
数组处理:上面的版本用新值覆盖旧的数组值。如果你想保留旧的数组值并添加新的,只需在else语句上方添加一个else If (current[key] instanceof array && updates[key] instanceof array) current[key] = current[key].concat(updates[key])块,你就都设置好了。