两个对象。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()相同。

有办法做到这一点吗?


当前回答

许多答案使用数十行代码,或者需要向项目添加一个新库,但如果您使用递归,这只是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])块,你就都设置好了。

其他回答

我在加载缓存redux状态时遇到了这个问题。如果我只是加载缓存的状态,我会遇到错误的新应用程序版本与更新的状态结构。

前面已经提到过,lodash提供了merge函数,我使用了这个函数:

const currentInitialState = configureState().getState();
const mergedState = _.merge({}, currentInitialState, cachedState);
const store = configureState(mergedState);

Ramda是一个很好的javascript函数库,它有mergeDeepLeft和mergeDeepRight。这些方法都能解决这个问题。请在这里查看文档:https://ramdajs.com/docs/#mergeDeepLeft

对于问题中的具体例子,我们可以使用:

import { mergeDeepLeft } from 'ramda'
const x = { a: { a: 1 } }
const y = { a: { b: 1 } }
const z = mergeDeepLeft(x, y)) // {"a":{"a":1,"b":1}}

简单递归解

使用对象。条目,遍历其中一个对象。如果条目不存在,则添加该条目;如果条目是对象,则递归。

常量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)

当涉及到宿主对象或比值包更复杂的任何类型的对象时,这个问题就不那么简单了

do you invoke a getter to obtain a value or do you copy over the property descriptor? what if the merge target has a setter (either own property or in its prototype chain)? Do you consider the value as already-present or call the setter to update the current value? do you invoke own-property functions or copy them over? What if they're bound functions or arrow functions depending on something in their scope chain at the time they were defined? what if it's something like a DOM node? You certainly don't want to treat it as simple object and just deep-merge all its properties over into how to deal with "simple" structures like arrays or maps or sets? Consider them already-present or merge them too? how to deal with non-enumerable own properties? what about new subtrees? Simply assign by reference or deep clone? how to deal with frozen/sealed/non-extensible objects?

另一件需要记住的事情是:包含循环的对象图。这通常不难处理——简单地保留一组已经访问过的源对象——但经常被遗忘。

您可能应该编写一个深度合并函数,它只期望原始值和简单对象(结构化克隆算法最多可以处理的那些类型)作为合并源。如果遇到它不能处理的东西,或者只是通过引用而不是深度合并进行赋值,则抛出。

换句话说,没有一种适合所有人的算法,您要么必须使用自己的算法,要么寻找恰好涵盖您的用例的库方法。

我使用lodash:

import _ = require('lodash');
value = _.merge(value1, value2);