deepmerge vs merge-deep vs deep-assign vs assign-deep vs object-assign-deep
Deep Merging and Object Assignment Comparison
1 Year
deepmergemerge-deepdeep-assignassign-deepobject-assign-deepSimilar Packages:
What's Deep Merging and Object Assignment?

Deep merging and object assignment libraries in JavaScript provide functionality to combine multiple objects into one, handling nested properties and arrays. These libraries are useful for tasks like merging configuration objects, combining state in applications, or creating deep copies of objects while preserving their structure. They differ in their approach to handling conflicts, mutability, and performance, making it essential to choose the right one based on your project's needs. For example, deepmerge is known for its robust handling of nested merges and conflicts, while assign-deep focuses on deep assigning properties from source objects to a target object, allowing for more control over the merging process.

Package Weekly Downloads Trend
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
deepmerge40,245,5552,78131.2 kB542 years agoMIT
merge-deep1,148,880111-144 years agoMIT
deep-assign187,396247-06 years agoMIT
assign-deep59,56278-76 years agoMIT
object-assign-deep27,49271-97 years agoMIT
Feature Comparison: deepmerge vs merge-deep vs deep-assign vs assign-deep vs object-assign-deep

Deep Merging vs. Deep Assigning

  • deepmerge:

    deepmerge specializes in deep merging objects, handling nested properties, arrays, and conflicts. It merges values from multiple sources into a target object, allowing for more complex merging strategies and conflict resolution compared to simple assignment.

  • merge-deep:

    merge-deep provides deep merging functionality, combining properties from multiple objects into one. It handles nested structures and merges values, making it suitable for scenarios where you need to combine multiple objects while preserving their hierarchy.

  • deep-assign:

    deep-assign is similar to assign-deep but emphasizes efficient deep assignment of properties from multiple source objects to a target object. It handles nested properties and ensures that all source values are assigned to the target without merging them.

  • assign-deep:

    assign-deep focuses on deep assigning properties from source objects to a target object, ensuring that nested properties are assigned without overwriting existing values. It does not merge objects but rather assigns values from one or more sources to the target.

  • object-assign-deep:

    object-assign-deep implements deep property assignment, recursively assigning values from source objects to a target object. It mimics the behavior of Object.assign but works at a deeper level, ensuring that nested properties are assigned correctly.

Conflict Resolution

  • deepmerge:

    deepmerge provides advanced conflict resolution by allowing you to define custom merging strategies for different types of values (e.g., arrays, objects). It intelligently merges nested properties and can handle conflicts based on the strategies you configure, making it more flexible and powerful for complex merging scenarios.

  • merge-deep:

    merge-deep resolves conflicts by merging values from multiple objects. If a property exists in both the target and source objects, it merges them based on their types (e.g., arrays are concatenated, objects are merged recursively), providing a more comprehensive approach to handling overlapping properties.

  • deep-assign:

    deep-assign similarly does not resolve conflicts. It assigns values from multiple sources to the target object, with the last source value taking precedence in case of overlapping properties. There is no built-in mechanism for merging conflicting values.

  • assign-deep:

    assign-deep does not handle conflicts since it only assigns values from source objects to the target. If a nested property exists in both the source and target, the value from the source will be assigned, but no merging or conflict resolution occurs.

  • object-assign-deep:

    object-assign-deep does not resolve conflicts; it simply assigns values from source objects to the target. If a nested property exists in both the source and target, the value from the source will overwrite the target's value, similar to the behavior of Object.assign.

Mutability

  • deepmerge:

    deepmerge is immutable by default, meaning it creates a new object with the merged values instead of modifying the original objects. This approach helps prevent side effects and makes the merging process safer, especially in functional programming contexts.

  • merge-deep:

    merge-deep is mutable, as it modifies the target object by merging properties from the source objects. It is important to be aware of this behavior to avoid unintended mutations in your code.

  • deep-assign:

    deep-assign is also mutable, as it directly modifies the target object by assigning properties from the source objects. Care should be taken to avoid mutating objects that are shared across different parts of the application.

  • assign-deep:

    assign-deep is mutable, meaning it modifies the target object directly by assigning values from the source objects. This can lead to unintended side effects if the target object is used elsewhere in the code.

  • object-assign-deep:

    object-assign-deep is mutable, as it modifies the target object by recursively assigning values from the source objects. This can lead to changes in the target object, so it is advisable to use it with caution.

Performance

  • deepmerge:

    deepmerge may have performance overhead due to its comprehensive merging capabilities and support for customizable merging strategies. While it is efficient for most scenarios, the performance can vary depending on the complexity of the objects being merged and the merging strategies used.

  • merge-deep:

    merge-deep is lightweight and performs well for deep merging objects. It is suitable for applications that require quick and efficient merging without the overhead of additional features or complexity.

  • deep-assign:

    deep-assign is designed for efficiency and performs well when deep assigning properties from multiple source objects. Its simplicity and lack of complex merging logic contribute to its fast performance, making it suitable for most use cases.

  • assign-deep:

    assign-deep is performant for deep assigning properties, especially when dealing with a limited number of source objects. However, its performance may degrade with a large number of nested properties or sources due to its recursive nature.

  • object-assign-deep:

    object-assign-deep is efficient for deep assigning properties, especially when working with a small number of source objects. Its performance is comparable to other deep assignment libraries, but it may slow down with highly nested structures.

Ease of Use: Code Examples

  • deepmerge:

    Deep Merging with deepmerge

    const deepmerge = require('deepmerge');
    
    const target = { a: { b: 1, c: [1, 2] }, d: 4 };
    const source = { a: { b: 2, c: [3, 4] }, d: 5 };
    
    const merged = deepmerge(target, source);
    console.log(merged);
    // Output: { a: { b: 2, c: [1, 2, 3, 4] }, d: 5 }
    
  • merge-deep:

    Deep Merging with merge-deep

    const mergeDeep = require('merge-deep');
    
    const target = { a: { b: 1 }, c: 3 };
    const source = { a: { b: 2 }, d: 4 };
    
    const merged = mergeDeep(target, source);
    console.log(merged);
    // Output: { a: { b: 2 }, c: 3, d: 4 }
    
  • deep-assign:

    Deep Assigning with deep-assign

    const deepAssign = require('deep-assign');
    
    const target = { a: { b: 1 }, c: 3 };
    const source1 = { a: { b: 2 } };
    const source2 = { d: 4 };
    
    deepAssign(target, source1, source2);
    console.log(target);
    // Output: { a: { b: 2 }, c: 3, d: 4 }
    
  • assign-deep:

    Deep Assigning with assign-deep

    const assignDeep = require('assign-deep');
    
    const target = { a: { b: 1 }, c: 3 };
    const source = { a: { b: 2 }, d: 4 };
    
    assignDeep(target, source);
    console.log(target);
    // Output: { a: { b: 2 }, c: 3, d: 4 }
    
  • object-assign-deep:

    Deep Assigning with object-assign-deep

    const objectAssignDeep = require('object-assign-deep');
    
    const target = { a: { b: 1 }, c: 3 };
    const source = { a: { b: 2 }, d: 4 };
    
    objectAssignDeep(target, source);
    console.log(target);
    // Output: { a: { b: 2 }, c: 3, d: 4 }
    
How to Choose: deepmerge vs merge-deep vs deep-assign vs assign-deep vs object-assign-deep
  • deepmerge:

    Opt for deepmerge if you need a comprehensive solution for deep merging objects that handles nested properties, arrays, and conflicts intelligently. It provides customizable merging strategies, making it suitable for complex scenarios where you need fine-grained control over how properties are merged.

  • merge-deep:

    Use merge-deep when you want a lightweight and easy-to-use library for deep merging objects. It is ideal for projects that require a simple merging solution without the overhead of additional features or complexity.

  • deep-assign:

    Select deep-assign if you require a straightforward and efficient way to deep assign properties from multiple source objects to a target object. It is designed for simplicity and performance, making it a good choice for projects where you want to minimize complexity.

  • assign-deep:

    Choose assign-deep if you need a simple and lightweight solution for deep assigning properties from one or more source objects to a target object. It is particularly useful when you want to ensure that nested properties are assigned without overwriting the entire object.

  • object-assign-deep:

    Choose object-assign-deep if you want a straightforward implementation of deep property assignment that mimics the native Object.assign method but works recursively. It is useful for projects that need a clear and concise way to deep assign properties without introducing external dependencies.

README for deepmerge

deepmerge

Merges the enumerable properties of two or more objects deeply.

UMD bundle is 723B minified+gzipped

Getting Started

Example Usage

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 do:

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.

Include

deepmerge exposes a CommonJS entry point:

const merge = require('deepmerge')

The ESM entry point was dropped due to a Webpack bug.

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.

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:

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.

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.

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.

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 do:

npm test

License

MIT