<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Scribe]]></title><description><![CDATA[Software Engineer]]></description><link>https://scribe.elijahthis.com</link><generator>RSS for Node</generator><lastBuildDate>Thu, 16 Apr 2026 01:37:49 GMT</lastBuildDate><atom:link href="https://scribe.elijahthis.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Object Cloning in JavaScript (Deep vs. Shallow Copies) - A Comprehensive Guide]]></title><description><![CDATA[Introduction
In the world of JavaScript, understanding how data is copied and referenced is crucial for preventing bugs and ensuring the correct behavior of applications. One of the most common sources of confusion is the difference between deep and ...]]></description><link>https://scribe.elijahthis.com/object-cloning-in-javascript-deep-vs-shallow-copies-a-comprehensive-guide</link><guid isPermaLink="true">https://scribe.elijahthis.com/object-cloning-in-javascript-deep-vs-shallow-copies-a-comprehensive-guide</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[js]]></category><category><![CDATA[json]]></category><category><![CDATA[#JavaScript #Cloning #ObjectCloning #ArrayCloning #DeepCloning #ShallowCloning #SpreadOperator #JSONSerialization #DataManipulation #CodeExamples #WebDevelopment #ProgrammingTips #DataIntegrity #BestPractices #CodeSnippets]]></category><category><![CDATA[Deep Copy v/s Shallow Copy]]></category><dc:creator><![CDATA[Elijah Oyerinde]]></dc:creator><pubDate>Mon, 18 Sep 2023 10:39:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1694823629480/df4c528e-d65b-45f5-aa73-37a95cc7acef.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>In the world of JavaScript, understanding how data is copied and referenced is crucial for preventing bugs and ensuring the correct behavior of applications. One of the most common sources of confusion is the difference between deep and shallow copies.</p>
<p>What are the differences between a deep copy and a shallow copy in JavaScript? Let us find out in this article.</p>
<p>Bonus: At the end of this article, I will also share my recommendations based on different factors and situations.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li><p><strong>Basic JavaScript Knowledge</strong></p>
</li>
<li><p><strong>Familiarity with Objects and Arrays:</strong> An understanding of how objects and arrays work, including how to create, access, and modify their properties and elements.</p>
</li>
</ul>
<hr />
<h2 id="heading-understanding-reference-values">Understanding Reference Values</h2>
<p>If you know anything about working with primitive data types (Strings, Numbers, Booleans, etc.), your default response to cloning data is assigning it to a new variable. With primitive data types, this is the end of the story, as a brand new independent value gets created and stored in memory, with no ties to the original. <strong>Changes to this value do NOT affect the original, and vice versa.</strong></p>
<p>That, unfortunately, is not the case with composite data types (Objects and Arrays). Let us compare their different behaviors:</p>
<h3 id="heading-primitive-types">Primitive Types</h3>
<p>Take a look at the example below:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Numbers</span>
<span class="hljs-keyword">let</span> num1 = <span class="hljs-number">7</span>
<span class="hljs-keyword">let</span> num2 = num1

<span class="hljs-built_in">console</span>.log(num2)    <span class="hljs-comment">// 7</span>

num1 = <span class="hljs-number">10</span>

<span class="hljs-built_in">console</span>.log(num1)    <span class="hljs-comment">// 10</span>
<span class="hljs-built_in">console</span>.log(num2)    <span class="hljs-comment">// 7</span>
</code></pre>
<p>We assigned <code>7</code> to the variable <code>num1</code>, assigned the value of <code>num1</code> (i.e. <code>7</code>) to the variable <code>num2</code>, then changed the value of <code>num1</code> to <code>10</code>. When we log both variables, we observe that <code>num1</code> has been updated to <code>10</code>, while num2 is still <code>7</code>. This is the default behavior of primitive types.</p>
<p>Next, let us create a function that modifies a primitive type:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Strings</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">modifyString</span>(<span class="hljs-params">input</span>) </span>{
    input += <span class="hljs-string">" --modified"</span>
    <span class="hljs-keyword">return</span> input
}

<span class="hljs-keyword">let</span> student1 = <span class="hljs-string">"Akin"</span>
<span class="hljs-keyword">let</span> student2 = modifyString(student1)

<span class="hljs-built_in">console</span>.log(student1)    <span class="hljs-comment">// "Akin"</span>
<span class="hljs-built_in">console</span>.log(student2)    <span class="hljs-comment">// "Akin --modified"</span>
</code></pre>
<p>Here, we've introduced a new function: <code>modifyString</code>. This function takes a string as its parameter and returns a modified version of that string, marked with the <code>"--modified"</code> flag. Initially, we assigned the value <code>"Akin"</code> to <code>student1</code>. Then, we passed <code>student1</code> to the <code>modifyString</code> function and assigned the result to <code>student2</code>. The outcome is as follows: <code>student1</code> remains unchanged as <code>"Akin"</code>, while <code>student2</code> receives the <code>"--modified"</code> flag.</p>
<p>This is also consistent with the behavior of primitive types.</p>
<h3 id="heading-reference-types">Reference Types</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> num1 = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>]
<span class="hljs-keyword">let</span> num2 = num1

<span class="hljs-built_in">console</span>.log(num2)    <span class="hljs-comment">// [1, 2, 3, 4, 5, 6]</span>

num1[<span class="hljs-number">2</span>] = <span class="hljs-number">10</span>

<span class="hljs-built_in">console</span>.log(num1)    <span class="hljs-comment">// [1, 2, 10, 4, 5, 6]</span>
<span class="hljs-built_in">console</span>.log(num2)    <span class="hljs-comment">// [1, 2, 10, 4, 5, 6]</span>
</code></pre>
<p>Notice how when we change the third element of <code>num1</code> from <code>3</code> to <code>10</code>, it reflects on <code>num2</code> also. This is unlike the behavior of the primitive types we have considered so far.</p>
<p>Next, let us create a function that modifies a reference type:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">modifyArray</span>(<span class="hljs-params">input</span>) </span>{
    input.push(<span class="hljs-number">99</span>)
    <span class="hljs-keyword">return</span> input
}

<span class="hljs-keyword">let</span> numList = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>]
<span class="hljs-keyword">let</span> numList_2 = modifyArray(numList)

<span class="hljs-built_in">console</span>.log(numList) <span class="hljs-comment">// [1, 2, 3, 4, 5, 6, 99]</span>
<span class="hljs-built_in">console</span>.log(numList_2) <span class="hljs-comment">// [1, 2, 3, 4, 5, 6, 99]</span>
</code></pre>
<p>Here, we've introduced a new function: <code>modifyArray</code>. This function takes an array as its parameter and returns a modified version of that array, with the element <code>99</code> added to the end. Initially, we assigned the array <code>[1, 2, 3, 4, 5, 6]</code> to <code>numList</code>. Then, we passed <code>numList</code> to the <code>modifyArray</code> function and assigned the result to <code>numList_2</code>. The outcome is as follows: both <code>numList</code> and <code>numList_2</code> get updated to <code>[1, 2, 3, 4, 5, 6, 99]</code>.</p>
<p>You will encounter this behavior with arrays and objects in JavaScript. That is the default behavior in JavaScript, and it happens because arrays, functions, and objects are composite data types, which are also sometimes referred to as <strong>reference types.</strong> That means that when you reassign a reference type to a new variable, you are simply copying a reference to the same object in memory and not the object itself.</p>
<p>What if that is not what you want? What if the functionality of your program relies on the creation of unique and independent clones? Let us discuss your options.</p>
<hr />
<h1 id="heading-shallow-copies">Shallow Copies</h1>
<p>Let us begin by understanding shallow copies. When you shallow copy an array or object in JavaScript, you create a new array or object, such that <strong>only the top-level structure is duplicated</strong>. <strong>All nested properties are still shared between the original and the copy.</strong></p>
<h3 id="heading-important-definitions"><strong>Important definitions:</strong></h3>
<ul>
<li><p><strong><em>Top-level Element in Arrays</em></strong>*: An element that directly belongs to the array and is not nested within any other arrays or objects within it. e.g. elements* <code>1</code><em>,</em> <code>2</code><em>,</em> <code>3</code><em>, and</em> <code>7</code> <em>in the array</em> <code>[1, 2, 3, [4, 5, 6], 7]</code></p>
</li>
<li><p><strong><em>Top-level Element in Objects</em></strong>*: A property-value pair in an object that is directly defined within the object itself and is not nested within any other objects. e.g. properties* <code>a</code> <em>and</em> <code>b</code> <em>in the object</em> <code>{a: 1, b: 2, c: {x: 1, y: 2} }</code></p>
</li>
</ul>
<h3 id="heading-creating-shallow-copies">Creating Shallow Copies</h3>
<p>In JavaScript, there are three major means of creating shallow copies:</p>
<ol>
<li><p>Spread operator (<code>...</code>)</p>
</li>
<li><p><code>Object.assign()</code></p>
</li>
<li><p><code>Array.from()</code></p>
</li>
</ol>
<p>What's all the talk without examples?</p>
<ol>
<li><p><strong>Spread Operator (</strong><code>...</code><strong>)</strong></p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> teamArr = [<span class="hljs-string">"John"</span>, <span class="hljs-string">"Will"</span>, [<span class="hljs-string">"Ali"</span>, <span class="hljs-string">"Angie"</span>, <span class="hljs-string">"Chike"</span>]]
 <span class="hljs-keyword">const</span> shallowTeamArr = [...teamArr]
 <span class="hljs-built_in">console</span>.log(shallowTeamArr)    <span class="hljs-comment">// ["John", "Will", ["Ali", "Angie", "Chike"]]</span>

 teamArr[<span class="hljs-number">1</span>] = <span class="hljs-string">"Ben"</span>
 teamArr[<span class="hljs-number">2</span>][<span class="hljs-number">0</span>] = <span class="hljs-string">"Kalu"</span>

 <span class="hljs-built_in">console</span>.log(teamArr)           <span class="hljs-comment">// ["John", "Ben", ["Kalu", "Angie", "Chike"]]</span>
 <span class="hljs-built_in">console</span>.log(shallowTeamArr)    <span class="hljs-comment">// ["John", "Will", ["Kalu", "Angie", "Chike"]]</span>
</code></pre>
<p> In this example, I'm only updating the original array (<code>teamArr</code>), and, of course, changes at the top level work as expected. Only the name in <code>teamArr</code> is changed (from <code>"Will"</code> to <code>"Ben"</code>). Its equivalent in <code>shallowTeamArr</code> remains the same.</p>
<p> Now, let's take a look at the nested array. When I swap out <code>"Ali"</code> for <code>"Kalu"</code> in <code>teamArr</code>, the change is reflected in <code>shallowTeamArr</code>. This behavior sums up shallow copies in a nutshell.</p>
<p> This behavior is also observed with objects, whether we use the spread operator (<code>...</code>) or JavaScript's <code>Object.assign</code> method. This is illustrated in the following examples:</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> userObj = {
   <span class="hljs-attr">name</span>: <span class="hljs-string">"John"</span>,
   <span class="hljs-attr">car</span>: { <span class="hljs-attr">maker</span>: <span class="hljs-string">"Audi"</span>, <span class="hljs-attr">model</span>: <span class="hljs-string">"R8"</span> }
 }

 <span class="hljs-keyword">const</span> shallowUserObj = {...userObj}
 <span class="hljs-built_in">console</span>.log(shallowUserObj)
 <span class="hljs-comment">/*
 {
   name: "John",
   car: { maker: "Audi", model: "R8" }
 }    */</span>

 userObj.name = <span class="hljs-string">"Charlie"</span>
 userObj.car.model = <span class="hljs-string">"RS6"</span>

 <span class="hljs-built_in">console</span>.log(userObj)
 <span class="hljs-comment">/*
 {
   name: "Charlie",
   car: { maker: "Audi", model: "RS6" }
 }    */</span>

 <span class="hljs-built_in">console</span>.log(shallowUserObj)
 <span class="hljs-comment">/*
 {
   name: "John",
   car: { maker: "Audi", model: "RS6" }
 }    */</span>
</code></pre>
</li>
<li><p><code>Object.assign()</code></p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> userObj = {
   <span class="hljs-attr">name</span>: <span class="hljs-string">"John"</span>,
   <span class="hljs-attr">car</span>: { <span class="hljs-attr">maker</span>: <span class="hljs-string">"Audi"</span>, <span class="hljs-attr">model</span>: <span class="hljs-string">"R8"</span> }
 }

 <span class="hljs-keyword">const</span> shallowUserObj = <span class="hljs-built_in">Object</span>.assign({}, userObj)
 <span class="hljs-built_in">console</span>.log(shallowUserObj)
 <span class="hljs-comment">/*
 {
   name: "John",
   car: { maker: "Audi", model: "R8" }
 }    */</span>

 userObj.name = <span class="hljs-string">"Charlie"</span>
 userObj.car.model = <span class="hljs-string">"RS6"</span>

 <span class="hljs-built_in">console</span>.log(userObj)
 <span class="hljs-comment">/*
 {
   name: "Charlie",
   car: { maker: "Audi", model: "RS6" }
 }    */</span>

 <span class="hljs-built_in">console</span>.log(shallowUserObj)
 <span class="hljs-comment">/*
 {
   name: "John",
   car: { maker: "Audi", model: "RS6" }
 }    */</span>
</code></pre>
</li>
<li><p><code>Array.from()</code></p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> teamArr = [<span class="hljs-string">"John"</span>, <span class="hljs-string">"Will"</span>, [<span class="hljs-string">"Ali"</span>, <span class="hljs-string">"Angie"</span>, <span class="hljs-string">"Chike"</span>]]
 <span class="hljs-keyword">const</span> duplicatedTeamArr = <span class="hljs-built_in">Array</span>.from(teamArr)
 <span class="hljs-built_in">console</span>.log(duplicatedTeamArr)    <span class="hljs-comment">// logs ["John", "Will", ["Ali", "Angie", "Chike"]]</span>

 teamArr[<span class="hljs-number">1</span>] = <span class="hljs-string">"Ben"</span>
 teamArr[<span class="hljs-number">2</span>][<span class="hljs-number">0</span>] = <span class="hljs-string">"Kalu"</span>

 <span class="hljs-built_in">console</span>.log(teamArr)    <span class="hljs-comment">// logs ["John", "Ben", ["Kalu", "Angie", "Chike"]]</span>
 <span class="hljs-built_in">console</span>.log(duplicatedTeamArr)    <span class="hljs-comment">// logs ["John", "Will", ["Kalu", "Angie", "Chike"]]</span>
</code></pre>
</li>
</ol>
<p>I'm sure you can already picture more than a few scenarios where this would be undesirable. So, how do we "fix" this behavior? Deep copies.</p>
<hr />
<h1 id="heading-deep-copies">Deep Copies</h1>
<p>When you perform a deep copy of an array or object in JavaScript, you create a new array or object in which <strong><em>every level of the object or array structure is duplicated</em></strong>*.* All properties are replicated and have no connection to the original, aside from containing the same values. <strong><em>You can envision this copy as a wholly independent version of the object with no shared properties, whether they are nested or not.</em></strong></p>
<h3 id="heading-creating-deep-copies">Creating Deep copies</h3>
<p>When it comes to implementing deep copies from scratch, the recursive approach stands out as our preferred tool of choice.</p>
<p>Here are a few methods:</p>
<ol>
<li><p>Recursive approach</p>
</li>
<li><p><code>JSON.parse()</code> + <code>JSON.stringify()</code></p>
</li>
<li><p><code>structuredClone()</code></p>
</li>
<li><p>Lodash's <code>cloneDeep()</code></p>
</li>
</ol>
<p>Let us try out some examples:</p>
<ol>
<li><p><strong>Recursive approach</strong></p>
<pre><code class="lang-javascript"> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deepCopy</span>(<span class="hljs-params">obj</span>) </span>{
   <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> obj !== <span class="hljs-string">'object'</span> || obj === <span class="hljs-literal">null</span>) {
     <span class="hljs-keyword">return</span> obj;
   }

   <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Array</span>.isArray(obj)) {
     <span class="hljs-keyword">return</span> obj.map(deepCopy);
   }

   <span class="hljs-keyword">const</span> newObj = {};
   <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> key <span class="hljs-keyword">in</span> obj) {
     newObj[key] = deepCopy(obj[key]);
   }

   <span class="hljs-keyword">return</span> newObj;
 }

 <span class="hljs-comment">/* ----------------- Examples ----------------- */</span>
 <span class="hljs-keyword">const</span> userObj = {
   <span class="hljs-attr">name</span>: <span class="hljs-string">"John"</span>,
   <span class="hljs-attr">car</span>: { <span class="hljs-attr">maker</span>: <span class="hljs-string">"Audi"</span>, <span class="hljs-attr">model</span>: <span class="hljs-string">"R8"</span> }
 }
 <span class="hljs-keyword">const</span> deepCopiedUserObject = deepCopy(userObj)

 <span class="hljs-built_in">console</span>.log(deepCopiedUserObject)
 <span class="hljs-comment">/*
 {
   name: "John",
   car: { maker: "Audi", model: "R8" }
 }    */</span>

 deepCopiedUserObject.name = <span class="hljs-string">"Charlie"</span>
 deepCopiedUserObject.car.model = <span class="hljs-string">"RS6"</span>

 <span class="hljs-built_in">console</span>.log(userObj);
 <span class="hljs-comment">/*
 {
   name: "John",
   car: { maker: "Audi", model: "R8" }
 }    */</span>

 <span class="hljs-built_in">console</span>.log(deepCopiedUserObject); 
 <span class="hljs-comment">/*
 {
   name: "Charlie",
   car: { maker: "Audi", model: "RS6" }
 }    */</span>
</code></pre>
<p> All done! Notice how only <code>deepCopiedUserObject</code> is updated in this example? His <code>name</code> changes to "Charlie," and his <code>car</code> <code>model</code> changes to the <code>"RS6"</code>, all while leaving <code>userObj</code> untouched and free from interference. This is the desired outcome – <code>deepCopiedUserObject</code> is an independent clone.</p>
<p> I could conclude this article here, but let us explore other options to better inform our decisions.</p>
</li>
<li><p><code>JSON.parse()</code> <strong>+</strong> <code>JSON.stringify()</code></p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> userObj = {
   <span class="hljs-attr">name</span>: <span class="hljs-string">"John"</span>,
   <span class="hljs-attr">car</span>: { <span class="hljs-attr">maker</span>: <span class="hljs-string">"Audi"</span>, <span class="hljs-attr">model</span>: <span class="hljs-string">"R8"</span> }
 }
 <span class="hljs-keyword">const</span> jsonString = <span class="hljs-built_in">JSON</span>.stringify(userObj)
 <span class="hljs-keyword">const</span> deepCopiedUserObject = <span class="hljs-built_in">JSON</span>.parse(jsonString)
 <span class="hljs-built_in">console</span>.log(deepCopiedUserObject)
 <span class="hljs-comment">/*
 {
   name: "John",
   car: { maker: "Audi", model: "R8" }
 }    */</span>

 deepCopiedUserObject.name = <span class="hljs-string">"Charlie"</span>
 deepCopiedUserObject.car.model = <span class="hljs-string">"RS6"</span>

 <span class="hljs-built_in">console</span>.log(userObj);
 <span class="hljs-comment">/*
 {
   name: "John",
   car: { maker: "Audi", model: "R8" }
 }    */</span>

 <span class="hljs-built_in">console</span>.log(deepCopiedUserObject); 
 <span class="hljs-comment">/*
 {
   name: "Charlie",
   car: { maker: "Audi", model: "RS6" }
 }    */</span>
</code></pre>
<p> Works just as well, or does it? This method utilizes the <code>JSON.parse()</code> and <code>JSON.stringify()</code> methods available on the built-in <code>JSON</code> namespace to serialize and deserialize objects to and from JSON format. The underlying concept involves converting our object into a string (a non-reference data type), then transforming it back into an object and assigning it to a new variable.</p>
<p> <mark>WARNING: This method is essentially a hack and is a less-than-perfect solution known to have several shortcomings, including:</mark></p>
<ul>
<li><p><strong>Data Loss:</strong> <code>JSON.stringify()</code> cannot serialize certain JavaScript data types, such as functions, <code>undefined</code> values, <code>null</code>, <code>Date()</code>, and objects with cyclic references. When such data types are encountered, they are either omitted or converted to null in the JSON string, leading to data loss.</p>
</li>
<li><p><strong>Loss of functionality</strong></p>
</li>
<li><p><strong>Performance issues:</strong> cloning with <code>JSON.parse(JSON.stringify())</code> can get very slow, especially as the object gets larger.</p>
</li>
</ul>
</li>
<li><p><code>structuredClone()</code></p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> userObj = {
   <span class="hljs-attr">name</span>: <span class="hljs-string">"John"</span>,
   <span class="hljs-attr">car</span>: { <span class="hljs-attr">maker</span>: <span class="hljs-string">"Audi"</span>, <span class="hljs-attr">model</span>: <span class="hljs-string">"R8"</span> }
 }
 <span class="hljs-keyword">const</span> deepCopiedUserObject = structuredClone(userObj)
 <span class="hljs-built_in">console</span>.log(deepCopiedUserObject)
 <span class="hljs-comment">/*
 {
   name: "John",
   car: { maker: "Audi", model: "R8" }
 }    */</span>

 deepCopiedUserObject.name = <span class="hljs-string">"Charlie"</span>
 deepCopiedUserObject.car.model = <span class="hljs-string">"RS6"</span>

 <span class="hljs-built_in">console</span>.log(userObj);
 <span class="hljs-comment">/*
 {
   name: "John",
   car: { maker: "Audi", model: "R8" }
 }    */</span>
 <span class="hljs-built_in">console</span>.log(deepCopiedUserObject); 
 <span class="hljs-comment">/*
 {
   name: "Charlie",
   car: { maker: "Audi", model: "RS6" }
 }    */</span>
</code></pre>
<p> This does the job perfectly! The <code>structuredClone()</code> method is part of the HTML Living Standard (HTML5) and allows you to create clones of structured data, including complex objects and cyclic structures. <code>structuredClone()</code> is designed to handle complex objects, including DOM elements and custom classes, and <strong>creates deep copies by default</strong>.</p>
<p> It has the added advantage of being a built-in JavaScript API that is present in all modern browsers.</p>
</li>
<li><p><strong>Lodash's</strong> <code>cloneDeep()</code></p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> _ = <span class="hljs-built_in">require</span>(<span class="hljs-string">"lodash"</span>)

 <span class="hljs-comment">/* ----------------- Examples ----------------- */</span>
 <span class="hljs-keyword">const</span> userObj = {
   <span class="hljs-attr">name</span>: <span class="hljs-string">"John"</span>,
   <span class="hljs-attr">car</span>: { <span class="hljs-attr">maker</span>: <span class="hljs-string">"Audi"</span>, <span class="hljs-attr">model</span>: <span class="hljs-string">"R8"</span> }
 }
 <span class="hljs-keyword">const</span> deepCopiedUserObject = _.cloneDeep(userObj)
 <span class="hljs-built_in">console</span>.log(deepCopiedUserObject)
 <span class="hljs-comment">/*
 {
   name: "John",
   car: { maker: "Audi", model: "R8" }
 }    */</span>

 deepCopiedUserObject.name = <span class="hljs-string">"Charlie"</span>
 deepCopiedUserObject.car.model = <span class="hljs-string">"RS6"</span>

 <span class="hljs-built_in">console</span>.log(userObj);
 <span class="hljs-comment">/*
 {
   name: "John",
   car: { maker: "Audi", model: "R8" }
 }    */</span>

 <span class="hljs-built_in">console</span>.log(deepCopiedUserObject); 
 <span class="hljs-comment">/*
 {
   name: "Charlie",
   car: { maker: "Audi", model: "RS6" }
 }    */</span>
</code></pre>
<p> While not a built-in JavaScript API, the Lodash library provides a <code>cloneDeep()</code> function that creates deep copies of objects and arrays. It is optimized to handle even the most complex data structures reliably and efficiently.</p>
</li>
</ol>
<h2 id="heading-my-recommendation">My recommendation</h2>
<p><strong>You will encounter situations where a shallow copy is sufficient. When you do, stick with the spread operator (</strong><code>...</code><strong>). When you find you need a deep copy though,</strong> <code>structuredClone()</code> <strong>is your best bet. If your project already has Lodash though, you might want to pull out the</strong> <code>cloneDeep()</code> <strong>method, as it is even more performant than the already efficient</strong> <code>structuredClone()</code><strong>.</strong></p>
<h2 id="heading-wrapping-up">Wrapping up</h2>
<p>In conclusion, understanding the nuances of deep and shallow copying in JavaScript is a pivotal skill for any developer. When you find yourself needing to preserve the integrity of unique object states or history, deep copying is your ally. For instance, consider a <strong>version control system</strong> or <strong>undo functionality</strong> in an application, where <strong><em>deep copying ensures each version remains distinct</em>.</strong></p>
<p>On the other hand, when optimizing performance and memory is paramount or when maintaining relationships between large data structures is necessary, shallow copying shines. Imagine a <strong>complex hierarchical menu system</strong> or a <strong>state management system</strong> in a frontend framework, where <em>shallow copying maintains references and ensures efficient updates.</em></p>
<p>By mastering both techniques, you empower yourself to choose the right tool for the job, making your code more efficient, maintainable, and resilient.</p>
<p>Happy hacking!</p>
]]></content:encoded></item></channel></rss>