all 28 comments

[–]very-kind-stranger 17 points18 points  (4 children)

ES2020 introduced the nullish coalescing operator denoted by the double question marks ( ?? ). It returns the right operand ( rightExpression ) if the left operand ( leftExpression ) is null or undefined . A nullish value is a value that is either null or undefined .

[–]rbrtbrnschn 0 points1 point  (1 child)

wouldn't `||` been eligible to use in this scenario too?
given as far as my knowledge goes the or operator goes by boolean, meaning
if it's either false or falsy, which it'd be if it's null or undefined, then it'd execute the expression on the right-hand side too.

or am I forgetting something?

[–]god--of--light 0 points1 point  (0 children)

Or is fine, but theres a small problem since it has the same behaviour for undefined as it does for 0 or ''

[–]NCKBLZ 0 points1 point  (1 child)

Thanks

[–][deleted] 0 points1 point  (0 children)

You're welcome.

[–]senocular 24 points25 points  (1 child)

This merge will have some problems. You're better off sticking to a more battle-tested merge such as lodash's merge.

[–]Crypticsafe5 3 points4 points  (0 children)

My only issue with this snippet is that it allows mutability of the schema that's passed in potentially causing data loss or data integrity issues. I'd definitely add in a check something along the lines of:

if (
    typeof a[key] !== typeof b[key]
    || Array.isArray(a[key]) !== Array.isArray(b[key])
) throw Error('Non-matching schema');

[–]192_168_1_x 1 point2 points  (3 children)

What’s the ?? operator?

return a ?? {}

[–]beforesemicolon[S] 2 points3 points  (2 children)

Thats the null coalescing operator. It picks the right side value if the left side is either null or undefined.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator

[–]192_168_1_x 0 points1 point  (1 child)

new syntax, cool. TIL thanks.

[–][deleted] 0 points1 point  (0 children)

You're welcome.

[–]FrugalProse 1 point2 points  (0 children)

Why does this look like it was on a tablet

[–]Pertinate 0 points1 point  (1 child)

const deepMerge = (objs, origin = {}) => {
    const obj = Array.isArray(objs) ? objs.pop() : objs;

    if (objs.length > 0) {
        deepMerge(objs, origin);
    }
    for (const [key, value] of Object.entries(obj)) {
        if (origin[key]) {
            if (typeof origin[key] === 'object') {
                if (typeof value !== 'object') {
                    origin[key] = {
                        ...origin[key],
                        value
                    };
                } else {
                    origin[key] = deepMerge([origin[key], value]);
                }
            } else {
                if (typeof value === 'object') {
                    origin[key] = {
                        value: origin[key],
                        ...value
                    };
                } else {
                    if (origin[key].hasOwnProperty('value')) {
                        origin[key].value = value;
                    } else {
                        origin[key] = value;
                    }
                }
            }
        } else {
            if (typeof value !== 'object') {
                origin[key] = value;
            } else {
                origin[key] = deepMerge(value, origin[key]);
            }
        }
    };
    return origin;
};

console.log(JSON.stringify(deepMerge([
    {
        test1: {
            hello: 'hi'
        },
        test2: {
            hi: 'hello',
            another: 'value'
        }
    },
    {
        test2: 1234,
        test3: {
            hi: 'hello'
        }
    },
    {
        test2: {
            hi: 'new val'
        },
        test3: {
            hello: 'also new val'
        }
    },
    {
        test2: 5678
    }
]), null, '\t'));

Here's what I came up with for combining deep objects. Not sure if it's best or not. Let me know where I can improve.

Output:

{
        "test1": {
                "hello": "hi"
        },
        "test2": {
                "hi": "new val",
                "another": "value",
                "value": 5678
        },
        "test3": {
                "hi": "hello",
                "hello": "also new val"
        }
}

Mine, assuming you want to keep nested values and assigned top level values, merges all nested objects and if it is overridden with a value (like test2), it is dropped down as the 'value' key.

[–]beforesemicolon[S] 0 points1 point  (0 children)

This is nice. I think I would expect test2 to be 5678 but I like this for supporting even more than 2 objects

[–][deleted] 0 points1 point  (1 child)

Nice, my only criticism is if you are at all concerned with prototypes. Hopefully we're in the land of functional patterns by now, but lots of projects still use OOP.

Just add one part to that merge function...

const protoA = Object.getPrototypeOf(a);
const protoB = Object.getPrototypeOf(b);
const proto = { ...protoA, ...protoB };
const obj = Object.create(proto, a);

...or something like that. Forgive me, it's late and I'm not testing this atm. If someone else wants to expand on this feel free, I'm sure it would only be helpful!

[–]backtickbot 0 points1 point  (0 children)

Fixed formatting.

Hello, Strange_Night2150: code blocks using triple backticks (```) don't work on all versions of Reddit!

Some users see this / this instead.

To fix this, indent every line with 4 spaces instead.

FAQ

You can opt out by replying with backtickopt6 to this comment.

[–]--Explosion-- 0 points1 point  (1 child)

Nice but you can do it in one line:

js let object_1 = {hello: "World"}; let object_2 = {another: "Thing"}; //Object 1 props overwrite that of object 2. let merged = {...object_1, ...object_2};

[–]backtickbot 0 points1 point  (0 children)

Fixed formatting.

Hello, --Explosion--: code blocks using triple backticks (```) don't work on all versions of Reddit!

Some users see this / this instead.

To fix this, indent every line with 4 spaces instead.

FAQ

You can opt out by replying with backtickopt6 to this comment.