简体   繁体   English

如何合并两个 JavaScript 对象的属性而不喜欢 null 值?

[英]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
}

I suggest using Lodash mergeWith for this:我建议为此使用Lodash mergeWith

const obj1 = {a: null, b: "b"} 
const obj2 = {a: "a", b: null}

const result = _.mergeWith({}, obj1, obj2,
  (a, b) => b === null ? a : undefined
)

// result: {a: "a", b: "b"}

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:它适用于nullundefined值:

 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))遍历它们的键、值并排除undefinednull的对象

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM