Skip to content

Commit

Permalink
Combine merge-objects
Browse files Browse the repository at this point in the history
  • Loading branch information
Chalarangelo committed Mar 23, 2024
1 parent 3681337 commit 6780c48
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 45 deletions.
15 changes: 9 additions & 6 deletions content/redirects.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1036,12 +1036,6 @@
- from: /js/s/assert-valid-keys
to: /js/s/assert-object-key-validity
status: 301!
- from: /js/s/deep-merge
to: /js/s/deep-merge-objects
status: 301!
- from: /js/s/merge
to: /js/s/merge-objects
status: 301!
- from: /js/s/unwind
to: /js/s/unwind-object
status: 301!
Expand Down Expand Up @@ -2764,3 +2758,12 @@
- from: /js/s/get-nested-value-in-object
to: /js/s/get-nested-object-value
status: 301!
- from: /js/s/deep-merge
to: /js/s/merge-objects
status: 301!
- from: /js/s/deep-merge-objects
to: /js/s/merge-objects
status: 301!
- from: /js/s/merge
to: /js/s/merge-objects
status: 301!
28 changes: 0 additions & 28 deletions content/snippets/js/s/deep-merge-objects.md

This file was deleted.

90 changes: 79 additions & 11 deletions content/snippets/js/s/merge-objects.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,36 @@
---
title: Merge objects
type: snippet
title: Merge two or more JavaScript objects
shortTitle: Merge objects
type: story
language: javascript
tags: [object,array]
tags: [object,array,function]
cover: guitar-living-room
dateModified: 2020-10-21
excerpt: Learn how to combine two or more objects into a single object in JavaScript.
dateModified: 2024-03-20
---

Creates a new object from the combination of two or more objects.
JavaScript arrays are fairly easy to merge, using the spread operator (`...`) or `Array.prototype.concat()`. Merging objects, however, is a little more complex, but can be done if you know the right techniques.

- Use `Array.prototype.reduce()` combined with `Object.keys()` to iterate over all objects and keys.
- Use `Object.prototype.hasOwnProperty()` and `Array.prototype.concat()` to append values for keys existing in multiple objects.
## Built-in methods

Both the spread operator (`...`) and `Object.assign()` can be used to merge two or more objects into a single object. However, these methods only perform a **shallow merge**, meaning that nested objects are not merged. They also have the drawback of **overwriting properties with the same key**.

```js
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };

const merged = { ...obj1, ...obj2 };
// { a: 1, b: 3, c: 4 }

const merged2 = Object.assign({}, obj2, obj1);
// { b: 2, c: 4, a: 1 }
```

## Combining values with the same key

Instead of overwriting properties with the same key, we usually want to combine their values. This can be done by **checking if the key already exists** in the resulting object and appending the value to an array if it does.

In order to perform this, we can use `Object.keys()` to **iterate** over all objects and keys, and `Object.prototype.hasOwnProperty()` to check if the key already exists in the resulting object. Then, we can use `Array.prototype.concat()` to **append** the values for keys that exist in multiple objects. This also allows us to preserve single values, if they only exist in one object.

```js
const merge = (...objs) =>
Expand All @@ -25,15 +45,63 @@ const merge = (...objs) =>
{}
);

const object = {
const obj1 = {
a: [{ x: 2 }, { y: 4 }],
b: 1
};
const other = {
const obj2 = {
a: { z: 3 },
b: [2, 3],
c: 'foo'
};
merge(object, other);
// { a: [ { x: 2 }, { y: 4 }, { z: 3 } ], b: [ 1, 2, 3 ], c: 'foo' }

merge(obj1, obj2);
// {
// a: [ { x: 2 }, { y: 4 }, { z: 3 } ],
// b: [ 1, 2, 3 ],
// c: 'foo'
// }
```

## Deeply merging objects

If you need to merge objects that contain **nested objects**, you might want to handle nested values differently. This can be done by passing a function that handles the merging of individual keys, allowing you to **customize the merging process**. You may, for example, want to merge arrays or objects, or overwrite values for certain keys.

In order to do so, we can use `Object.keys()` to get the keys of both objects, create a `Set` from them, and use the spread operator (`...`) to create an **array of all the unique keys**. We can then use `Array.prototype.reduce()` to add each unique key to the object, using the provided function to combine the values of the two given objects.

```js
const deepMerge = (a, b, fn) =>
[...new Set([...Object.keys(a), ...Object.keys(b)])].reduce(
(acc, key) => ({ ...acc, [key]: fn(key, a[key], b[key]) }),
{}
);

const obj1 = {
a: true,
b: [1, 2, 3],
c: { d: 4, e: 5 },
f: 'foo',
};
const obj2 = {
a: false,
b: [4, 5, 6],
c: { d: 6, g: 7 },
f: 'bar',
};

const concatFn = (key, a, b) => {
if (Array.isArray(a) && Array.isArray(b)) return a.concat(b);
if (typeof a === 'object' && typeof b === 'object')
return deepMerge(a, b, concatFn);
if (typeof a === 'string' && typeof b === 'string') return [a, b].join(' ');
return b ?? a;
};

deepMerge(obj1, obj2, concatFn);
// {
// a: false,
// b: [ 1, 2, 3, 4, 5, 6 ]
// c: { d: 6, e: 5, g: 7 },
// f: 'foo bar'
// }
```

0 comments on commit 6780c48

Please sign in to comment.