可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have the following 2 JavaScript Objects:
let o1 = {
entities: {
1: {
text: "fooo",
nested: {
ids: [1, 2, 3],
flag: true
}
}
}
};
let o2 = {
ids: [4, 5, 6]
}
I want to merge them without mutating them, to get an Object which looks like this:
let o3 = {
entities: {
1: {
text: "fooo",
nested: {
ids: [1, 2, 3, 4, 5, 6],
flag: true
}
}
}
};
There could be n entities
, but only the one defined by entityId
should be affected.
What I tried:
let entityId = 1;
let o3 = Object.assign({}, o1, {
entities: Object.assign({}, o1.entities, {
[entityId]: Object.assign({}, o1.entities[entityId].nested,
{ ids: [...o1.entities[entityId].nested.ids, ...o2.ids] }
)
})
});
The problem is that text: "fooo",nested:
completely disappear.
Is my aproach right? Could this code be optimized?
回答1:
Since you tagged Redux, I will assume you are using React and suggest you use the immutability helper - https://facebook.github.io/react/docs/update.html
Your code would look like this:
let o3 = update(o1, {
entities: {
[entityId]: {
nested: {
ids: {
$push: [4, 5, 6]
}
}
}
}
})
ES6
Your logic is correct, but you are missing the nested
object in your code:
let o3 = Object.assign({}, o1, {
entities: Object.assign({}, o1.entities, {
[entityId]: Object.assign({}, o1.entities[entityId], {
nested : Object.assign({}, o1.entities[entityId].nested ,{
ids: [...o1.entities[entityId].nested.ids, ...o2.ids] })
}
)
})
});
回答2:
If you know your data isn't going to include any dates or methods you could use the JSON deep-clone trick:
let o3 = JSON.parse(JSON.stringify(o1));
Array.prototype.push.apply(o3.entities[1].nested.ids, o2.ids);
回答3:
Well, your first problem is this bit:
{
[entityId]: Object.assign({}, o1.entities[entityId].nested,
where you're copying the value of o1.entities[1].nested
into the key o3.entities[1]
and thus losing the other keys from the object held in o1.entities[1]
.
This is hard to see because, as the other comments have indicated, this isn't very pretty code.
You wanted to (and meant to) use o1.entities[entityId]
instead, of course.
You have an additional problem, though, in that if you're only doing a deep copy on the part of o1
that you're currently interested in. Object.assign()
will copy object references, instead of creating entirely fresh objects. So if you later modify the value of o3.entities[1].text
, you will also be mutating o1.entities[1]
.
回答4:
Looks like you missed one layer of merging - your example code has entities.1.ids
instead of entities.1.nested.ids
. Try
let entityId = 1;
let o3 = Object.assign(
{},
o1,
{
entities: Object.assign(
{},
o1.entities,
{
[entityId]: Object.assign(
{},
o1.entities[entityId],
Object.assign(
{},
o1.entities[entityId].nested,
{ ids: [...o1.entities[entityId].nested.ids, ...o2.ids] }
)
)
}
)
}
);
At this point, you probably want to build up some intermediate variables from each of the Object.assign
calls just so you can keep track of everything a little better.
回答5:
I'd just do:
const merged = {
entities: {
[entityId]: {
text: o1.entities[entityId].text,
nested: {
ids: [...o1.entities[entityId].nested.ids, ...o2.ids],
flag: o1.entities[entityId].nested.flag
}
}
}
}