如何深度合并而不是浅层合并?
Object.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()
相同。
有没有办法做到这一点?
有谁知道ES6 / ES7规范中是否存在深度合并?
不,不是的。
我知道这是一个老问题,但ES2015 / ES6中最简单的解决方案实际上很简单,使用Object.assign(),
希望这有助于:
/**
* Simple object check.
* @param item
* @returns {boolean}
*/
export function isObject(item) {
return (item && typeof item === 'object' && !Array.isArray(item));
}
/**
* Deep merge two objects.
* @param target
* @param ...sources
*/
export function mergeDeep(target, ...sources) {
if (!sources.length) return target;
const source = sources.shift();
if (isObject(target) && isObject(source)) {
for (const key in source) {
if (isObject(source[key])) {
if (!target[key]) Object.assign(target, { [key]: {} });
mergeDeep(target[key], source[key]);
} else {
Object.assign(target, { [key]: source[key] });
}
}
}
return mergeDeep(target, ...sources);
}
用法示例:
mergeDeep(this, { a: { b: { c: 123 } } });
// or
const merged = mergeDeep({a: 1}, { b : { c: { d: { e: 12345}}}});
console.dir(merged); // { a: 1, b: { c: { d: [Object] } } }
你会在下面的答案中找到这个不变的版本。
请注意,这将导致循环引用无限递归。 如果您认为您会遇到这个问题,那么在这里有关于如何检测循环引用的一些很好的答案。
当涉及到主机对象或任何类型的比一包值更复杂的对象时,这个问题并不重要
还有一件事要记住:包含循环的对象图。 处理通常不难 - 只保留一Set
已经访问过的源对象 - 但经常被遗忘。
您可能应该编写一个深度合并函数,该函数仅将原始值和简单对象(至多是结构化克隆算法可处理的那些类型)视为合并源。 如果遇到无法处理的任何内容,或者仅通过引用分配而不是深度合并,则抛出它。
换句话说,没有一种万能的算法,你必须自己推出或寻找适合你的用例的库方法。
链接地址: http://www.djcxy.com/p/4693.html