You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
265 lines
5.5 KiB
265 lines
5.5 KiB
4 years ago
|
# deepmerge
|
||
|
|
||
|
Merges the enumerable properties of two or more objects deeply.
|
||
|
|
||
|
> UMD bundle is 723B minified+gzipped
|
||
|
|
||
|
## Getting Started
|
||
|
|
||
|
### Example Usage
|
||
|
<!--js
|
||
|
const merge = require('./')
|
||
|
-->
|
||
|
|
||
|
```js
|
||
|
const x = {
|
||
|
foo: { bar: 3 },
|
||
|
array: [{
|
||
|
does: 'work',
|
||
|
too: [ 1, 2, 3 ]
|
||
|
}]
|
||
|
}
|
||
|
|
||
|
const y = {
|
||
|
foo: { baz: 4 },
|
||
|
quux: 5,
|
||
|
array: [{
|
||
|
does: 'work',
|
||
|
too: [ 4, 5, 6 ]
|
||
|
}, {
|
||
|
really: 'yes'
|
||
|
}]
|
||
|
}
|
||
|
|
||
|
const output = {
|
||
|
foo: {
|
||
|
bar: 3,
|
||
|
baz: 4
|
||
|
},
|
||
|
array: [{
|
||
|
does: 'work',
|
||
|
too: [ 1, 2, 3 ]
|
||
|
}, {
|
||
|
does: 'work',
|
||
|
too: [ 4, 5, 6 ]
|
||
|
}, {
|
||
|
really: 'yes'
|
||
|
}],
|
||
|
quux: 5
|
||
|
}
|
||
|
|
||
|
merge(x, y) // => output
|
||
|
```
|
||
|
|
||
|
|
||
|
### Installation
|
||
|
|
||
|
With [npm](http://npmjs.org) do:
|
||
|
|
||
|
```sh
|
||
|
npm install deepmerge
|
||
|
```
|
||
|
|
||
|
deepmerge can be used directly in the browser without the use of package managers/bundlers as well: [UMD version from unpkg.com](https://unpkg.com/deepmerge/dist/umd.js).
|
||
|
|
||
|
|
||
|
### Include
|
||
|
|
||
|
deepmerge exposes a CommonJS entry point:
|
||
|
|
||
|
```
|
||
|
const merge = require('deepmerge')
|
||
|
```
|
||
|
|
||
|
The ESM entry point was dropped due to a [Webpack bug](https://github.com/webpack/webpack/issues/6584).
|
||
|
|
||
|
# API
|
||
|
|
||
|
|
||
|
## `merge(x, y, [options])`
|
||
|
|
||
|
Merge two objects `x` and `y` deeply, returning a new merged object with the
|
||
|
elements from both `x` and `y`.
|
||
|
|
||
|
If an element at the same key is present for both `x` and `y`, the value from
|
||
|
`y` will appear in the result.
|
||
|
|
||
|
Merging creates a new object, so that neither `x` or `y` is modified.
|
||
|
|
||
|
**Note:** By default, arrays are merged by concatenating them.
|
||
|
|
||
|
## `merge.all(arrayOfObjects, [options])`
|
||
|
|
||
|
Merges any number of objects into a single result object.
|
||
|
|
||
|
```js
|
||
|
const foobar = { foo: { bar: 3 } }
|
||
|
const foobaz = { foo: { baz: 4 } }
|
||
|
const bar = { bar: 'yay!' }
|
||
|
|
||
|
merge.all([ foobar, foobaz, bar ]) // => { foo: { bar: 3, baz: 4 }, bar: 'yay!' }
|
||
|
```
|
||
|
|
||
|
|
||
|
## Options
|
||
|
|
||
|
### `arrayMerge`
|
||
|
|
||
|
There are multiple ways to merge two arrays, below are a few examples but you can also create your own custom function.
|
||
|
|
||
|
Your `arrayMerge` function will be called with three arguments: a `target` array, the `source` array, and an `options` object with these properties:
|
||
|
|
||
|
- `isMergeableObject(value)`
|
||
|
- `cloneUnlessOtherwiseSpecified(value, options)`
|
||
|
|
||
|
#### `arrayMerge` example: overwrite target array
|
||
|
|
||
|
Overwrites the existing array values completely rather than concatenating them:
|
||
|
|
||
|
```js
|
||
|
const overwriteMerge = (destinationArray, sourceArray, options) => sourceArray
|
||
|
|
||
|
merge(
|
||
|
[1, 2, 3],
|
||
|
[3, 2, 1],
|
||
|
{ arrayMerge: overwriteMerge }
|
||
|
) // => [3, 2, 1]
|
||
|
```
|
||
|
|
||
|
#### `arrayMerge` example: combine arrays
|
||
|
|
||
|
Combines objects at the same index in the two arrays.
|
||
|
|
||
|
This was the default array merging algorithm pre-version-2.0.0.
|
||
|
|
||
|
```js
|
||
|
const combineMerge = (target, source, options) => {
|
||
|
const destination = target.slice()
|
||
|
|
||
|
source.forEach((item, index) => {
|
||
|
if (typeof destination[index] === 'undefined') {
|
||
|
destination[index] = options.cloneUnlessOtherwiseSpecified(item, options)
|
||
|
} else if (options.isMergeableObject(item)) {
|
||
|
destination[index] = merge(target[index], item, options)
|
||
|
} else if (target.indexOf(item) === -1) {
|
||
|
destination.push(item)
|
||
|
}
|
||
|
})
|
||
|
return destination
|
||
|
}
|
||
|
|
||
|
merge(
|
||
|
[{ a: true }],
|
||
|
[{ b: true }, 'ah yup'],
|
||
|
{ arrayMerge: combineMerge }
|
||
|
) // => [{ a: true, b: true }, 'ah yup']
|
||
|
```
|
||
|
|
||
|
### `isMergeableObject`
|
||
|
|
||
|
By default, deepmerge clones every property from almost every kind of object.
|
||
|
|
||
|
You may not want this, if your objects are of special types, and you want to copy the whole object instead of just copying its properties.
|
||
|
|
||
|
You can accomplish this by passing in a function for the `isMergeableObject` option.
|
||
|
|
||
|
If you only want to clone properties of plain objects, and ignore all "special" kinds of instantiated objects, you probably want to drop in [`is-plain-object`](https://github.com/jonschlinkert/is-plain-object).
|
||
|
|
||
|
```js
|
||
|
const isPlainObject = require('is-plain-object')
|
||
|
|
||
|
function SuperSpecial() {
|
||
|
this.special = 'oh yeah man totally'
|
||
|
}
|
||
|
|
||
|
const instantiatedSpecialObject = new SuperSpecial()
|
||
|
|
||
|
const target = {
|
||
|
someProperty: {
|
||
|
cool: 'oh for sure'
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const source = {
|
||
|
someProperty: instantiatedSpecialObject
|
||
|
}
|
||
|
|
||
|
const defaultOutput = merge(target, source)
|
||
|
|
||
|
defaultOutput.someProperty.cool // => 'oh for sure'
|
||
|
defaultOutput.someProperty.special // => 'oh yeah man totally'
|
||
|
defaultOutput.someProperty instanceof SuperSpecial // => false
|
||
|
|
||
|
const customMergeOutput = merge(target, source, {
|
||
|
isMergeableObject: isPlainObject
|
||
|
})
|
||
|
|
||
|
customMergeOutput.someProperty.cool // => undefined
|
||
|
customMergeOutput.someProperty.special // => 'oh yeah man totally'
|
||
|
customMergeOutput.someProperty instanceof SuperSpecial // => true
|
||
|
```
|
||
|
|
||
|
### `customMerge`
|
||
|
|
||
|
Specifies a function which can be used to override the default merge behavior for a property, based on the property name.
|
||
|
|
||
|
The `customMerge` function will be passed the key for each property, and should return the function which should be used to merge the values for that property.
|
||
|
|
||
|
It may also return undefined, in which case the default merge behaviour will be used.
|
||
|
|
||
|
```js
|
||
|
const alex = {
|
||
|
name: {
|
||
|
first: 'Alex',
|
||
|
last: 'Alexson'
|
||
|
},
|
||
|
pets: ['Cat', 'Parrot']
|
||
|
}
|
||
|
|
||
|
const tony = {
|
||
|
name: {
|
||
|
first: 'Tony',
|
||
|
last: 'Tonison'
|
||
|
},
|
||
|
pets: ['Dog']
|
||
|
}
|
||
|
|
||
|
const mergeNames = (nameA, nameB) => `${nameA.first} and ${nameB.first}`
|
||
|
|
||
|
const options = {
|
||
|
customMerge: (key) => {
|
||
|
if (key === 'name') {
|
||
|
return mergeNames
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const result = merge(alex, tony, options)
|
||
|
|
||
|
result.name // => 'Alex and Tony'
|
||
|
result.pets // => ['Cat', 'Parrot', 'Dog']
|
||
|
```
|
||
|
|
||
|
|
||
|
### `clone`
|
||
|
|
||
|
*Deprecated.*
|
||
|
|
||
|
Defaults to `true`.
|
||
|
|
||
|
If `clone` is `false` then child objects will be copied directly instead of being cloned. This was the default behavior before version 2.x.
|
||
|
|
||
|
|
||
|
# Testing
|
||
|
|
||
|
With [npm](http://npmjs.org) do:
|
||
|
|
||
|
```sh
|
||
|
npm test
|
||
|
```
|
||
|
|
||
|
|
||
|
# License
|
||
|
|
||
|
MIT
|