deepmerge vs underscore vs ramda vs merge-deep vs deepdash vs lodash vs object-path
JavaScript Object Manipulation Libraries
deepmergeunderscoreramdamerge-deepdeepdashlodashobject-pathSimilar Packages:
JavaScript Object Manipulation Libraries

JavaScript Object Manipulation Libraries are tools that provide functions to create, modify, traverse, and manipulate objects and their properties. These libraries offer a wide range of functionalities, such as deep cloning, merging, transforming, and querying objects, making it easier for developers to handle complex data structures in a more efficient and readable manner. They help streamline tasks that involve working with nested objects, arrays, and other data types, providing utility functions that can save time and reduce code complexity. Examples of popular object manipulation libraries include Lodash, Underscore.js, and Ramda, each offering unique features and design philosophies to cater to different programming needs and styles.

Npm Package Weekly Downloads Trend
3 Years
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
deepmerge37,390,0882,82031.2 kB583 years agoMIT
underscore11,575,46327,384906 kB52a year agoMIT
ramda7,632,27224,1081.2 MB1473 months agoMIT
merge-deep981,564112-145 years agoMIT
deepdash82,078279-275 years agoMIT
lodash061,555-1035 years agoMIT
object-path01,066-354 years agoMIT
Feature Comparison: deepmerge vs underscore vs ramda vs merge-deep vs deepdash vs lodash vs object-path

Deep Merging

  • deepmerge:

    deepmerge specializes in deep merging objects, handling nested properties and arrays with customizable merge strategies. It is designed specifically for merging, making it a reliable choice for this task.

  • underscore:

    underscore offers basic deep merging capabilities through its _.extend and _.merge functions, but it is not as comprehensive or specialized as Lodash or other merging libraries.

  • ramda:

    ramda provides deep merging capabilities through its functional programming approach. It allows for more customizable and composable merging strategies, making it suitable for projects that require a functional style of merging.

  • merge-deep:

    merge-deep provides a simple and efficient implementation of deep merging for objects. It recursively merges properties, making it a lightweight option for projects that need straightforward merging functionality.

  • deepdash:

    deepdash does not provide deep merging capabilities as its primary focus is on deep traversal and manipulation of nested objects and arrays.

  • lodash:

    lodash offers deep merging capabilities through its _.merge function, which recursively merges properties of source objects into a target object. It is versatile and well-optimized for various merging scenarios.

  • object-path:

    object-path does not perform deep merging but allows for deep manipulation of object properties using a path-based approach. It is more focused on getting, setting, and deleting properties at any depth rather than merging.

Deep Traversal

  • deepmerge:

    deepmerge does not provide deep traversal capabilities as it is focused solely on merging objects.

  • underscore:

    underscore offers basic traversal capabilities through functions like _.each, _.map, and _.filter, but it does not specialize in deep traversal or provide any unique features for handling nested structures.

  • ramda:

    ramda provides deep traversal capabilities through its functional programming functions. It allows for composable and immutable traversal of nested data, making it suitable for projects that emphasize functional design.

  • merge-deep:

    merge-deep does not provide deep traversal functionality, as its primary focus is on merging objects.

  • deepdash:

    deepdash excels at deep traversal of nested objects and arrays, allowing you to perform operations like mapping, filtering, and reducing at any depth. It provides a simple API for traversing and manipulating complex data structures.

  • lodash:

    lodash offers deep traversal capabilities through functions like _.forEach, _.map, and _.filter, which can be used recursively on nested objects and arrays. It provides a flexible and efficient way to traverse and manipulate data at any depth.

  • object-path:

    object-path allows for deep traversal of object properties using a path-based syntax. It enables you to access, modify, and delete properties at any depth, making it easy to work with nested structures.

Immutability

  • deepmerge:

    deepmerge does not enforce immutability, but it creates new objects during the merging process, leaving the original objects unchanged.

  • underscore:

    underscore does not enforce immutability, as its functions can modify data in place. However, it provides utility functions that can be used in an immutable manner if the developer chooses to do so.

  • ramda:

    ramda promotes immutability by design, providing pure functions that do not modify the original data. It encourages a functional programming style that avoids side effects and mutable state.

  • merge-deep:

    merge-deep does not enforce immutability, as it modifies the target object during the merging process. However, it does not alter the source objects, keeping them unchanged.

  • deepdash:

    deepdash does not enforce immutability by default, but it allows for immutable operations if implemented by the user during traversal and manipulation.

  • lodash:

    lodash does not enforce immutability, but many of its functions can be used in an immutable manner if the developer chooses to do so. It provides both mutable and immutable operations, giving developers the flexibility to choose.

  • object-path:

    object-path does not enforce immutability, but it allows for immutable operations if the user implements them while manipulating properties. It provides functions that can be used in both mutable and immutable contexts.

Functional Programming Support

  • deepmerge:

    deepmerge is not designed with functional programming in mind, as it focuses on merging objects rather than providing a functional API.

  • underscore:

    underscore supports functional programming concepts, such as higher-order functions, callbacks, and iterators. It provides a solid foundation for functional programming in JavaScript, but it is not as focused on functional purity as Ramda.

  • ramda:

    ramda is a functional programming library that emphasizes immutability, pure functions, and higher-order functions. It is designed to be used in a functional style, making it a great choice for projects that prioritize functional programming principles.

  • merge-deep:

    merge-deep does not provide functional programming features, as it is a simple utility for deep merging objects.

  • deepdash:

    deepdash does not specifically focus on functional programming but can be used in a functional style, especially during deep traversal and manipulation.

  • lodash:

    lodash supports functional programming through its modular design, higher-order functions, and support for currying and composition. It provides many functions that can be used in a functional style, making it versatile for different programming paradigms.

  • object-path:

    object-path does not focus on functional programming but provides a simple API for manipulating object properties that can be used in a functional style.

Ease of Use: Code Examples

  • deepmerge:

    Deep Merging with deepmerge

    import merge from 'deepmerge';
    
    const obj1 = { a: { b: 1 }, c: 3 };
    const obj2 = { a: { b: 2 }, c: 4 };
    
    const merged = merge(obj1, obj2);
    
    console.log(merged); // { a: { b: 2 }, c: 4 }
    
  • underscore:

    Deep Merging with underscore

    import { merge } from 'underscore';
    
    const obj1 = { a: { b: 1 }, c: 3 };
    const obj2 = { a: { b: 2 }, c: 4 };
    
    const merged = merge(obj1, obj2);
    
    console.log(merged); // { a: { b: 2 }, c: 4 }
    
  • ramda:

    Deep Property Manipulation with ramda

    import { set, view, lensPath } from 'ramda';
    
    const obj = { a: { b: { c: 1 } } };
    const lens = lensPath(['a', 'b', 'c']);
    
    const updatedObj = set(lens, 2, obj);
    console.log(view(lens, updatedObj)); // 2
    
  • merge-deep:

    Deep Merging with merge-deep

    import mergeDeep from 'merge-deep';
    
    const obj1 = { a: { b: 1 }, c: 3 };
    const obj2 = { a: { b: 2 }, c: 4 };
    
    const merged = mergeDeep(obj1, obj2);
    
    console.log(merged); // { a: { b: 2 }, c: 4 }
    
  • deepdash:

    Deep Traversal with deepdash

    import { deepMap } from 'deepdash';
    
    const obj = { a: { b: { c: 1 } } };
    
    deepMap(obj, (value) => {
      if (typeof value === 'number') {
        return value * 2;
      }
    });
    
    console.log(obj); // { a: { b: { c: 2 } } }
    
  • lodash:

    Deep Merging with lodash

    import { merge } from 'lodash';
    
    const obj1 = { a: { b: 1 }, c: 3 };
    const obj2 = { a: { b: 2 }, c: 4 };
    
    const merged = merge(obj1, obj2);
    
    console.log(merged); // { a: { b: 2 }, c: 4 }
    
  • object-path:

    Deep Property Manipulation with object-path

    import { set, get, del } from 'object-path';
    
    const obj = { a: { b: { c: 1 } } };
    
    set(obj, 'a.b.c', 2);
    console.log(get(obj, 'a.b.c')); // 2
    
    del(obj, 'a.b.c');
    console.log(get(obj, 'a.b.c')); // undefined
    
How to Choose: deepmerge vs underscore vs ramda vs merge-deep vs deepdash vs lodash vs object-path
  • deepmerge:

    Select deepmerge when you need a straightforward solution for deep merging objects, especially when dealing with nested properties. It handles merging with customizable strategies for arrays and objects, making it ideal for configuration merging and similar tasks.

  • underscore:

    Choose underscore if you need a lightweight utility library that provides a solid set of functions for object manipulation, similar to Lodash but with a smaller footprint. It is a good choice for projects that require essential utility functions without the need for a comprehensive library.

  • ramda:

    Select ramda if you prefer a functional programming approach to object manipulation. It offers a rich set of curried and composable functions that promote immutability and side-effect-free programming, making it ideal for projects that emphasize functional design principles.

  • merge-deep:

    Use merge-deep if you want a lightweight and simple solution for deep merging objects without any dependencies. It is easy to use and perfect for projects where you need a no-frills merging function without the overhead of a larger library.

  • deepdash:

    Choose deepdash if you need to perform deep operations on nested objects and arrays, such as deep mapping, filtering, or reducing, while maintaining a simple and intuitive API. It is particularly useful for tasks that require traversing and manipulating deeply nested structures.

  • lodash:

    Opt for lodash if you require a comprehensive utility library with a wide range of functions for object manipulation, including deep cloning, merging, and manipulation. It is well-optimized, widely used, and offers a modular approach, allowing you to import only the functions you need.

  • object-path:

    Choose object-path if you need to work with deeply nested object properties using a simple string-based path syntax. It provides functions for getting, setting, deleting, and manipulating properties at any depth, making it great for handling dynamic and uncertain object structures.

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