[英]How to merge properties of two JavaScript objects and prefer not null values?
Here are two objects:这里有两个对象:
const obj1 = {a: null, b: "b"}
const obj2 = {a: "a", b: null}
How can I merge the two objects and get the following object?如何合并这两个对象并得到以下 object?
{a: "a", b: "b"}
I can do this:我可以做这个:
const merged = {...obj1, ...obj2}
But it returns this:但它返回这个:
{ a: "a", b: null }
Is there a way to merge two objects while prefering not null (nor empty, undefined, etc.) values?有没有办法合并两个对象而不喜欢 null (也不是空的,未定义的等)值?
function merge(obj1, obj2) {
answer = {}
for(key in obj1) {
if(answer[key] === undefined || answer[key] === null)
answer[key] = obj1[key];
}
for(key in obj2) {
if(answer[key] === undefined || answer[key] === null)
answer[key] = obj2[key];
}
return answer
}
Try this.尝试这个。
const obj1 = {a: null, b: "b"} const obj2 = {a: "a", b: null} const obj3 = {} for (var k in obj1) { obj3[k] = obj1[k] ? obj1[k] : obj2[k]; } console.log(obj3);
What about a simple forEach()
loop on object key
.对象
key
上的简单forEach()
循环怎么样。 It will work for both null
and undefined
values:它适用于
null
和undefined
值:
const obj1 = {a: null, b: "b"}; const obj2 = {a: "a", b: null}; const merged = {}; Object.keys(obj1).forEach((key) => merged[[key]] = obj1[key] ? obj1[key] : obj2[key]); console.log(merged);
I figured I could accomplish this by combining these libraries.我想我可以通过组合这些库来实现这一点。
" @ramda/mergedeepwith " is ported from ramda . “ @ramda/mergedeepwith ”是从ramda移植过来的。
" flat " is Flatten/unflatten nested Javascript objects. “ flat ”是 Flatten/unflatten 嵌套的 Javascript 个对象。
yarn add @ramda/mergedeepwith flat ramda
This is workaround.这是解决方法。
import { default as flat } from "flat"; import mergeDeepWith from "@ramda/mergedeepwith"; import * as R from "ramda"; const obj1 = { a: null, b: "bbb", c: { "c-1": "cccc", }, d: [ { "d-1": "ddd-1", }, { "d-2": null, }, { "d-3": [0, 1, "a", 100], // omit 0 }, ], }; const obj2 = { a: "aaa", b: null, c: { "c-1": null, }, d: [ { "d-1": null, }, { "d-2": "ddd-2", }, { "d-3": ["b", "c"], }, ], }; const flattenedObj1 = flat.flatten(obj1); const flattenedObj2 = flat.flatten(obj2); const mergedObj = R.mergeDeepWith( (x, y) => { if (x) return x; if (y) return y; return null; }, flattenedObj2, flattenedObj1 ); console.log(JSON.stringify(flat.unflatten(mergedObj), null, 2));
Output is here. Output 来了。
$ node index.js { "a": "aaa", "b": "bbb", "c": { "c-1": "cccc" }, "d": [ { "d-1": "ddd-1" }, { "d-2": "ddd-2" }, { "d-3": [ "b", "c", "a", 100 ] } ] }
function omitNull (obj) {
const keys = Object.keys(obj);
const _obj = {};
for (const key of keys) {
const value = obj[key];
if (value !== null) {
_obj[key] = value;
}
}
return _obj;
}
const merged = {
...omitNull(obj1),
...omitNull(obj2)
};
result = {};
for(key in obj1){
result[key] = obj1[key] === null ? obj2[key] : obj1[key];
}
this merges two objects in one loop这将两个对象合并到一个循环中
You could make a function that gets an array of objects as a parameter.您可以创建一个获取对象数组作为参数的函数。
This way, no matter how many objects you have, you will get the result of them merged together excluding the undefined and null values.这样,无论你有多少对象,你都会得到它们合并在一起的结果,不包括 undefined 和 null 值。 Just send them as an array.
只需将它们作为数组发送即可。
There you pass all your objects, map them, then iterate through their key,values with for (const [key, value] of Object.entries(obj))
and exclude the ones that are undefined
or null
在那里,您传递所有对象,映射它们,然后使用
for (const [key, value] of Object.entries(obj))
遍历它们的键、值并排除undefined
或null
的对象
See below见下文
const obj1 = { a: null, b: "goodb", c: 0, } const obj2 = { a: "gooda", b: null, c: undefined } function cleanObjects(arr) { let o = {} arr.map((obj) => { for (const [key, value] of Object.entries(obj)) { typeof value === 'undefined' || value === null ? delete obj[key] : o[key] = value; } }) return o; } const result = cleanObjects([obj1, obj2]) console.log(result)
Here's a modified version of the accepted answer:这是已接受答案的修改版本:
function merge(obj1, obj2) {
let merged = { ...obj1 }
for (key in obj2) {
if (merged[key] === undefined || merged[key] === null)
merged[key] = obj2[key];
}
return merged
}
You can extend the Javascript ObjectConstructor itself.您可以扩展 Javascript ObjectConstructor 本身。 Add a function
merge
, This overrides the next non-null value and adds all the objects' properties to one single object.添加一个函数
merge
,这会覆盖下一个非空值并将所有对象的属性添加到一个对象中。
/* @/utils.js */
Object.merge = function (...objs) {
const obj = {};
objs.reduce((prevObj, currentObj) => {
if (typeof prevObj === 'object' && typeof currentObj === 'object') Object.entries(currentObj).forEach(([k, v]) => {
obj[k] = v === null || v === undefined
? prevObj[k]
: v;
});
return obj;
}, {});
return obj;
};
/* @/app.js */
Object.merge(a,b,c,...z);
Object.merge = function (...objs) { const obj = {}; objs.reduce((prevObj, currentObj) => { if (typeof prevObj === 'object' && typeof currentObj === 'object') Object.entries(currentObj).forEach(([k, v]) => { obj[k] = v === null || v === undefined ? prevObj[k] : v; }); return obj; }, {}); return obj; } const john = { name: 'John Doe', age: 40, heigth: '5.3ft' } const jane = { name: 'Jane Doe', age: null, heigth: '4.1ft' } const mark = { name: 'Mark', age: 35, heigth: null } const ghost = { name: null, age: null, heigth: null, planet: 'unknown' } const noname = { name: null, age: 100, heigth: '100ft', planet: '100M-E' } console.log(Object.merge(john,jane,mark,ghost,noname))
function merge(obj1, obj2) { if (!obj1 && !obj2) return null if (!obj1) return obj2; if (!obj2) return obj1; result = {} const keys = [...new Set([...Object.keys(obj1), ...Object.keys(obj2)])]; keys.forEach(key => { result[key] = obj1[key] || obj2[key] }) return result } console.log(merge(null, undefined)) console.log(merge({ a: 1}, null)) console.log(merge(null, { b : 2})) console.log(merge(null, { })) console.log(merge({a: 1, b : null, c : undefined, d: 'd'}, { b : 2, c: 5, d: null}))
const obj1 = { a: null, b: "goodb", c: 0, d: 133, f: null } const obj2 = { a: "gooda", b: null, e: 1, c: undefined } function cleanObjects(arr) { let o = {} arr.map((obj) => { for (const [key, value] of Object.entries(obj)) { typeof value === 'undefined' || value === null? delete obj[key]: o[key] = value; } }) return o; } const result = cleanObjects([obj1, obj2]) console.log(result)
For completeness sake, someone should mention the Nullish coalescing operator为了完整起见,有人应该提到Nullish 合并运算符
So for top-level properties you can choose the not-nullish one:因此,对于顶级属性,您可以选择非无效属性:
const obj1 = { a: null, b: "b" }
const obj2 = { a: "a", b: null }
const obj3 = { foo: Infinity }
let merge = (...objects) =>
objects
.reduce((result, next) => ({ ...result, ...Object.entries(next)
.reduce((resultingEntries, [key, value]) => ({ ...resultingEntries, [key]: value ?? result[key] }), {})}))
merge(obj1, obj2, obj3)
// {a: "a", b: "b", foo: "c"}
If you also want to copy deeper properties, things start to get REALLY ugly:如果您还想复制更深层次的属性,事情就会开始变得非常难看:
let merge2 = (...objects) =>
objects
.reduce((result, next) => ({ ...result, ...Object.entries(next)
.reduce((resultingEntries, [key, value]) => ({ ...resultingEntries, [key]:
result && result[key] && typeof result[key] === 'object' // <- null unsafe here
? merge3(...objects.map(o => o && o[key]))
: value ?? result[key] // <- to here?
}), {})}))
Perhaps better to extract it to a function也许最好将其提取到 function
const getProps = (key, ...objects) => objects.filter(isntNullOrUndefined).map(o => o[key]).filter(isntNullOrUndefined)
const isntNullOrUndefined = x => x !== null && x !== undefined
const merge2 = (...objects) =>
objects
.filter(isntNullOrUndefined)
.reduce((acc, obj) => ({
...acc,
...Object
.keys(obj)
.filter(key => !(key in acc))
.filter(key => isntNullOrUndefined(obj[key]))
.reduce((acc2, key) => ({
...acc2,
[key]: typeof obj[key] === 'object'
? merge2(...getProps(key, ...objects))
: getProps(key, ...objects)[0]
}), {})
}), {})
The next step is to do it with iterators, which might be slicker than reduce
using the ??
下一步是用迭代器
??
,这可能比使用reduce
operator.操作员。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.