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
			| 
								 
											3 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
							 |