Home
Forums
New posts
Search forums
What's new
New posts
New resources
New profile posts
Latest activity
Resources
Latest reviews
Search resources
Members
Current visitors
New profile posts
Search profile posts
DMCA Policy
Log in
Register
What's new
Search
Search
Search titles only
By:
New posts
Search forums
Menu
Log in
Register
Install the app
Install
FEEL FREE TO SHARE TUTORIALS, YOUR SKILS & KNOWLEDGE ON CODING, SCRIPTS, THEMES, PLUGINS OR ANY RESOURCES YOU HAVE WITH THE COMMUNITY-
Click Here To Post Your Request,
JOIN COMPUTER REPAIR FORUM
Home
Forums
TUTORIALS
CODING TUTORIALS
Node.js
JavaScript Deep Merge
JavaScript is disabled. For a better experience, please enable JavaScript in your browser before proceeding.
You are using an out of date browser. It may not display this or other websites correctly.
You should upgrade or use an
alternative browser
.
Reply to thread
Message
<blockquote data-quote="codeguru" data-source="post: 55" data-attributes="member: 2"><p>I recently shared how you can <a href="https://davidwalsh.name/merge-objects" target="_blank">merge object properties with the spread operator</a> but this method has one big limitation: the spread operator merge isn’t a “deep” merge, meaning merges are recursive. Moreover nested object properties aren’t merged — the last value specified in the merge replaces the last, even when there are other properties that should exist.</p><p></p><p></p><p>const defaultPerson = {</p><p> name: 'Anon',</p><p> gender: 'Female',</p><p> hair: {</p><p> color: 'brown',</p><p> cut: 'long'</p><p> },</p><p> eyes: 'blue',</p><p> family: ['mom', 'dad']</p><p>};</p><p></p><p>const me = {</p><p> name: 'David Walsh',</p><p> gender: 'Male',</p><p> hair: {</p><p> cut: 'short'</p><p> },</p><p> family: ['wife', 'kids', 'dog']</p><p>};</p><p></p><p>const summary = {...defaultPerson, ...me};</p><p></p><p>/*</p><p>{ </p><p> "name":"David Walsh",</p><p> "gender":"Male",</p><p> "hair":{ </p><p> "cut":"short"</p><p> },</p><p> "eyes":"blue",</p><p> "family":[ </p><p> "wife",</p><p> "kids",</p><p> "dog"</p><p> ]</p><p>}</p><p>*/</p><p></p><p></p><p>In the sample above, you’ll notice that the [ICODE]hair[/ICODE] object’s [ICODE]color[/ICODE] is gone instead of merged because the spread operator simply keeps the last provided values, which in this case is [ICODE]me.hair[/ICODE]. The same merge problem applies to arrays — you’ll notice [ICODE]mom[/ICODE] and [ICODE]dad[/ICODE] aren’t merged from the [ICODE]defaultPerson[/ICODE] object’s [ICODE]family[/ICODE] array. Yikes!</p><p></p><p>Deep merging in JavaScript is important, especially with the common practice of “default” or “options” objects with many properties and nested objects that often get merged with instance-specific values. If you’re looking for a utility to help with deep merges, look no further than the tiny <a href="https://github.com/KyleAMathews/deepmerge" target="_blank">deepmerge utility</a>!</p><p></p><p>When you use the [ICODE]deepmerge[/ICODE] utility, you can recursively merge any number of objects (including arrays) into one final object. Let’s take a look!</p><p></p><p></p><p>const deepmerge = require('deepmerge');</p><p></p><p>// ...</p><p></p><p>const summary = deepmerge(defaultPerson, me);</p><p></p><p>/*</p><p>{ </p><p> "name":"David Walsh",</p><p> "gender":"Male",</p><p> "hair":{ </p><p> "color":"brown",</p><p> "cut":"short"</p><p> },</p><p> "eyes":"blue",</p><p> "family":[ </p><p> "mom",</p><p> "dad",</p><p> "wife",</p><p> "kids",</p><p> "dog"</p><p> ]</p><p>}</p><p>*/</p><p></p><p></p><p>[ICODE]deepmerge[/ICODE] can handle much more complicated merges: nested objects and [ICODE]deepmerge.all[/ICODE] to merge more than two objects:</p><p></p><p></p><p>const result = deepmerge.all([,</p><p> { level1: { level2: { name: 'David', parts: ['head', 'shoulders'] } } },</p><p> { level1: { level2: { face: 'meh', parts: ['knees', 'toes'] } } },</p><p> { level1: { level2: { eyes: 'more meh', parts: ['eyes'] } } },</p><p>]);</p><p></p><p>/*</p><p>{ </p><p> "level1":{ </p><p> "level2":{ </p><p> "name":"David",</p><p> "parts":[ </p><p> "head",</p><p> "shoulders",</p><p> "knees",</p><p> "toes",</p><p> "eyes"</p><p> ],</p><p> "face":"meh",</p><p> "eyes":"more meh"</p><p> }</p><p> }</p><p>}</p><p>*/</p><p></p><p></p><p>[ICODE]deepmerge[/ICODE] is an amazing utility is a relatively small amount of code:</p><p></p><p></p><p>function isMergeableObject(val) {</p><p> var nonNullObject = val && typeof val === 'object'</p><p></p><p> return nonNullObject</p><p> && Object.prototype.toString.call(val) !== '[object RegExp]'</p><p> && Object.prototype.toString.call(val) !== '[object Date]'</p><p>}</p><p></p><p>function emptyTarget(val) {</p><p> return Array.isArray(val) ? [] : {}</p><p>}</p><p></p><p>function cloneIfNecessary(value, optionsArgument) {</p><p> var clone = optionsArgument && optionsArgument.clone === true</p><p> return (clone && isMergeableObject(value)) ? deepmerge(emptyTarget(value), value, optionsArgument) : value</p><p>}</p><p></p><p>function defaultArrayMerge(target, source, optionsArgument) {</p><p> var destination = target.slice()</p><p> source.forEach(function(e, i) {</p><p> if (typeof destination<em> === 'undefined') {</em></p><p><em> destination<em> = cloneIfNecessary(e, optionsArgument)</em></em></p><p><em><em> } else if (isMergeableObject(e)) {</em></em></p><p><em><em> destination<em> = deepmerge(target<em>, e, optionsArgument)</em></em></em></em></p><p><em><em><em><em> } else if (target.indexOf(e) === -1) {</em></em></em></em></p><p><em><em><em><em> destination.push(cloneIfNecessary(e, optionsArgument))</em></em></em></em></p><p><em><em><em><em> }</em></em></em></em></p><p><em><em><em><em> })</em></em></em></em></p><p><em><em><em><em> return destination</em></em></em></em></p><p><em><em><em><em>}</em></em></em></em></p><p><em><em><em><em></em></em></em></em></p><p><em><em><em><em>function mergeObject(target, source, optionsArgument) {</em></em></em></em></p><p><em><em><em><em> var destination = {}</em></em></em></em></p><p><em><em><em><em> if (isMergeableObject(target)) {</em></em></em></em></p><p><em><em><em><em> Object.keys(target).forEach(function (key) {</em></em></em></em></p><p><em><em><em><em> destination[key] = cloneIfNecessary(target[key], optionsArgument)</em></em></em></em></p><p><em><em><em><em> })</em></em></em></em></p><p><em><em><em><em> }</em></em></em></em></p><p><em><em><em><em> Object.keys(source).forEach(function (key) {</em></em></em></em></p><p><em><em><em><em> if (!isMergeableObject(source[key]) || !target[key]) {</em></em></em></em></p><p><em><em><em><em> destination[key] = cloneIfNecessary(source[key], optionsArgument)</em></em></em></em></p><p><em><em><em><em> } else {</em></em></em></em></p><p><em><em><em><em> destination[key] = deepmerge(target[key], source[key], optionsArgument)</em></em></em></em></p><p><em><em><em><em> }</em></em></em></em></p><p><em><em><em><em> })</em></em></em></em></p><p><em><em><em><em> return destination</em></em></em></em></p><p><em><em><em><em>}</em></em></em></em></p><p><em><em><em><em></em></em></em></em></p><p><em><em><em><em>function deepmerge(target, source, optionsArgument) {</em></em></em></em></p><p><em><em><em><em> var array = Array.isArray(source);</em></em></em></em></p><p><em><em><em><em> var options = optionsArgument || { arrayMerge: defaultArrayMerge }</em></em></em></em></p><p><em><em><em><em> var arrayMerge = options.arrayMerge || defaultArrayMerge</em></em></em></em></p><p><em><em><em><em></em></em></em></em></p><p><em><em><em><em> if (array) {</em></em></em></em></p><p><em><em><em><em> return Array.isArray(target) ? arrayMerge(target, source, optionsArgument) : cloneIfNecessary(source, optionsArgument)</em></em></em></em></p><p><em><em><em><em> } else {</em></em></em></em></p><p><em><em><em><em> return mergeObject(target, source, optionsArgument)</em></em></em></em></p><p><em><em><em><em> }</em></em></em></em></p><p><em><em><em><em>}</em></em></em></em></p><p><em><em><em><em></em></em></em></em></p><p><em><em><em><em>deepmerge.all = function deepmergeAll(array, optionsArgument) {</em></em></em></em></p><p><em><em><em><em> if (!Array.isArray(array) || array.length < 2) {</em></em></em></em></p><p><em><em><em><em> throw new Error('first argument should be an array with at least two elements')</em></em></em></em></p><p><em><em><em><em> }</em></em></em></em></p><p><em><em><em><em></em></em></em></em></p><p><em><em><em><em> // we are sure there are at least 2 values, so it is safe to have no initial value</em></em></em></em></p><p><em><em><em><em> return array.reduce(function(prev, next) {</em></em></em></em></p><p><em><em><em><em> return deepmerge(prev, next, optionsArgument)</em></em></em></em></p><p><em><em><em><em> })</em></em></em></em></p><p><em><em><em><em>}</em></em></em></em></p><p><em><em><em><em></em></em></em></em></p><p><em><em><em><em></em></em></em></em></p><p><em><em><em><em>Little code with big functionality? That's my favorite type of utility! [ICODE]deepmerge[/ICODE] is used all over the web and for good reason!</em></em></em></em></p><p><em><em><em><em></em></em></em></em></p><p><em><em><em><em>The post <a href="https://davidwalsh.name/javascript-deep-merge" target="_blank">JavaScript Deep Merge</a> appeared first on <a href="https://davidwalsh.name" target="_blank">David Walsh Blog</a>.</em></em></em></em></p><p><em><em><em><em></em></em></em></em></p><p><em><em><em><em><a href="https://tkjs.us/dwb" target="_blank"><img src="https://davidwalsh.name/demo/tjs_block-1.svg" alt="" class="fr-fic fr-dii fr-draggable " style="" /></a></em></em></em></em></p><p><em><em><em><em></em></em></em></em></p><p><em><em><em><em><a href="https://davidwalsh.name/javascript-deep-merge" target="_blank">Continue reading...</a></em></em></em></em></p></blockquote><p></p>
[QUOTE="codeguru, post: 55, member: 2"] I recently shared how you can [URL='https://davidwalsh.name/merge-objects']merge object properties with the spread operator[/URL] but this method has one big limitation: the spread operator merge isn’t a “deep” merge, meaning merges are recursive. Moreover nested object properties aren’t merged — the last value specified in the merge replaces the last, even when there are other properties that should exist. const defaultPerson = { name: 'Anon', gender: 'Female', hair: { color: 'brown', cut: 'long' }, eyes: 'blue', family: ['mom', 'dad'] }; const me = { name: 'David Walsh', gender: 'Male', hair: { cut: 'short' }, family: ['wife', 'kids', 'dog'] }; const summary = {...defaultPerson, ...me}; /* { "name":"David Walsh", "gender":"Male", "hair":{ "cut":"short" }, "eyes":"blue", "family":[ "wife", "kids", "dog" ] } */ In the sample above, you’ll notice that the [ICODE]hair[/ICODE] object’s [ICODE]color[/ICODE] is gone instead of merged because the spread operator simply keeps the last provided values, which in this case is [ICODE]me.hair[/ICODE]. The same merge problem applies to arrays — you’ll notice [ICODE]mom[/ICODE] and [ICODE]dad[/ICODE] aren’t merged from the [ICODE]defaultPerson[/ICODE] object’s [ICODE]family[/ICODE] array. Yikes! Deep merging in JavaScript is important, especially with the common practice of “default” or “options” objects with many properties and nested objects that often get merged with instance-specific values. If you’re looking for a utility to help with deep merges, look no further than the tiny [URL='https://github.com/KyleAMathews/deepmerge']deepmerge utility[/URL]! When you use the [ICODE]deepmerge[/ICODE] utility, you can recursively merge any number of objects (including arrays) into one final object. Let’s take a look! const deepmerge = require('deepmerge'); // ... const summary = deepmerge(defaultPerson, me); /* { "name":"David Walsh", "gender":"Male", "hair":{ "color":"brown", "cut":"short" }, "eyes":"blue", "family":[ "mom", "dad", "wife", "kids", "dog" ] } */ [ICODE]deepmerge[/ICODE] can handle much more complicated merges: nested objects and [ICODE]deepmerge.all[/ICODE] to merge more than two objects: const result = deepmerge.all([, { level1: { level2: { name: 'David', parts: ['head', 'shoulders'] } } }, { level1: { level2: { face: 'meh', parts: ['knees', 'toes'] } } }, { level1: { level2: { eyes: 'more meh', parts: ['eyes'] } } }, ]); /* { "level1":{ "level2":{ "name":"David", "parts":[ "head", "shoulders", "knees", "toes", "eyes" ], "face":"meh", "eyes":"more meh" } } } */ [ICODE]deepmerge[/ICODE] is an amazing utility is a relatively small amount of code: function isMergeableObject(val) { var nonNullObject = val && typeof val === 'object' return nonNullObject && Object.prototype.toString.call(val) !== '[object RegExp]' && Object.prototype.toString.call(val) !== '[object Date]' } function emptyTarget(val) { return Array.isArray(val) ? [] : {} } function cloneIfNecessary(value, optionsArgument) { var clone = optionsArgument && optionsArgument.clone === true return (clone && isMergeableObject(value)) ? deepmerge(emptyTarget(value), value, optionsArgument) : value } function defaultArrayMerge(target, source, optionsArgument) { var destination = target.slice() source.forEach(function(e, i) { if (typeof destination[i] === 'undefined') { destination[i] = cloneIfNecessary(e, optionsArgument) } else if (isMergeableObject(e)) { destination[i] = deepmerge(target[i], e, optionsArgument) } else if (target.indexOf(e) === -1) { destination.push(cloneIfNecessary(e, optionsArgument)) } }) return destination } function mergeObject(target, source, optionsArgument) { var destination = {} if (isMergeableObject(target)) { Object.keys(target).forEach(function (key) { destination[key] = cloneIfNecessary(target[key], optionsArgument) }) } Object.keys(source).forEach(function (key) { if (!isMergeableObject(source[key]) || !target[key]) { destination[key] = cloneIfNecessary(source[key], optionsArgument) } else { destination[key] = deepmerge(target[key], source[key], optionsArgument) } }) return destination } function deepmerge(target, source, optionsArgument) { var array = Array.isArray(source); var options = optionsArgument || { arrayMerge: defaultArrayMerge } var arrayMerge = options.arrayMerge || defaultArrayMerge if (array) { return Array.isArray(target) ? arrayMerge(target, source, optionsArgument) : cloneIfNecessary(source, optionsArgument) } else { return mergeObject(target, source, optionsArgument) } } deepmerge.all = function deepmergeAll(array, optionsArgument) { if (!Array.isArray(array) || array.length < 2) { throw new Error('first argument should be an array with at least two elements') } // we are sure there are at least 2 values, so it is safe to have no initial value return array.reduce(function(prev, next) { return deepmerge(prev, next, optionsArgument) }) } Little code with big functionality? That's my favorite type of utility! [ICODE]deepmerge[/ICODE] is used all over the web and for good reason! The post [URL='https://davidwalsh.name/javascript-deep-merge']JavaScript Deep Merge[/URL] appeared first on [URL='https://davidwalsh.name']David Walsh Blog[/URL]. [URL='https://tkjs.us/dwb'][IMG]https://davidwalsh.name/demo/tjs_block-1.svg[/IMG][/URL] [url="https://davidwalsh.name/javascript-deep-merge"]Continue reading...[/url][/i][/i][/i][/i] [/QUOTE]
Insert quotes…
Verification
Post reply
Richest Freecoded User
Most Freecoin
freecoded
4,838 Freecoin
Davy200
590 Freecoin
J
Johnhendrick
575 Freecoin
S
Smith16
527 Freecoin
nathan69
426 Freecoin
Laureine
415 Freecoin
A
anajeen
370 Freecoin
C
codeguru
287 Freecoin
Tekera
267 Freecoin
A
Akubay
170 Freecoin
Home
Forums
TUTORIALS
CODING TUTORIALS
Node.js
JavaScript Deep Merge
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.
Accept
Learn more…
Top