≡ Menu

It happens to everyone when they start moving past simple scripts into more complex application architecture.

You hold an object in one variable.

You want to make changes to it without affecting the original state, so you decide to “copy” it to a new variable.

Then, disaster strikes. You change the “copy,” but five minutes later you realize the original has changed too.

You’ve introduced a bug that is notoriously hard to track down if you don’t know what to look for.

The root of this evil lies in how JavaScript (and many other languages) handles memory, leading to the crucial distinction between a Shallow Copy and a Deep Copy.

Here is your guide to never getting bitten by reference bugs again.


The “Why”: The 30-Second Memory Crash Course

Before we define shallow vs. deep, we have to understand why this happens at all.

If you copy a primitive (like a number: let a = 5; let b = a;), the computer actually creates a new “5” in a new memory slot. They are independent.

Objects are different.

Objects can be huge. If the computer duplicated the entire object every time you assigned it to a new variable, your app would grind to a halt. Instead, JavaScript takes a shortcut for efficiency.

When you create an object variable, the variable doesn’t contain the object data.

It contains a reference (a memory address) pointing to where that data lives on the heap.

When you do const copy = original, you aren’t copying the data; you are just copying the address. Now two variables point to the exact same house.

To actually duplicate the data, we need specific techniques.


Level 1: The Shallow Copy

A shallow copy is a halfway measure. It creates a brand new “container” object in memory, but it fills that container with the references found in the original object.

In plain English: A shallow copy disconnects the top-level object, but any nested objects (objects inside objects) are still shared properties.

The Modern Way: The Spread Operator ...

The most common way to create a shallow copy in modern JavaScript is using the spread syntax.

const player1 = {
    name: "Arthur",
    score: 100,
    inventory: { sword: "Iron" } // Nested object!
};

// Create a shallow copy
const player2 = { ...player1 };

// Let's change the top level
player2.name = "Lancelot";
console.log(player1.name); // "Arthur"
console.log(player2.name); // "Lancelot"
// SUCCESS! They are disconnected at the top level.

The Shallow Trap (The “Gotcha”)

Because it’s a shallow copy, it didn’t bother creating new space for the nested inventory object. It just copied the reference to it.

// Let's change the nested level on player 2
player2.inventory.sword = "Diamond";

// UH OH.
console.log(player1.inventory.sword); // "Diamond"
// FAIL! The nested objects are still linked.

When to use Shallow Copy:

Shallow copies are fast and efficient. Use them when your data structure is “flat” (no nested arrays or objects), or when you know for a fact you will only be editing top-level properties.


Level 2: The Deep Copy

A deep copy is the nuclear option.

It doesn’t just copy the top container. It looks inside, sees a nested object, creates brand new memory for that, looks inside that, and keeps going recursively until everything in the new tree is physically separate from the old tree.

The Modern Way: structuredClone()

For years, JavaScript didn’t have a built-in way to do this well. As of 2022, we finally have a native, efficient global function supported by all major browsers and Node.js: structuredClone().

const player1 = {
    name: "Arthur",
    inventory: { sword: "Iron" }
};

// Create a Deep Copy
const player2 = structuredClone(player1);

// Change the nested item on player 2
player2.inventory.sword = "Diamond";

console.log(player1.inventory.sword); // "Iron"
console.log(player2.inventory.sword); // "Diamond"
// SUCCESS! Total independence.

The “Hack” Way: JSON Stringify

Before structuredClone, developers used a notorious hack. They would convert the object into a plain text JSON string (which breaks all memory references because it’s just text), and then parse it back into a new object.

const deepCopy = JSON.parse(JSON.stringify(originalObject));

Warning: While this works for simple data, it is dangerous. The JSON method will delete Functions, turn undefined into null, and break complex types like Dates or Maps. Use structuredClone whenever possible.

When to use Deep Copy:

Use it when you have complex, nested state (like in a Redux store or a large configuration object) and you absolutely must ensure that changes to the new version do not bleed back into the old version.


Summary Cheat Sheet

If you are ever confused about which you need, remember this rule of thumb: If your object has more than one “layer” of curly braces {}, a shallow copy probably isn’t enough.

Feature Assignment (=) Shallow Copy ({…}) Deep Copy (structuredClone)
Creates new top-level container? No Yes Yes
Clones nested objects? No No (References shared) Yes (Fully independent)
Performance Speed Instant Fast Slower (depending on size)
Use Case Pointing to same data Flat data structures Complex/Nested State

Useful links below:

Let me & my team build you a money making website/blog for your business https://bit.ly/tnrwebsite_service

Get Bluehost hosting for as little as $1.99/month (save 75%)…https://bit.ly/3C1fZd2

Best email marketing automation solution on the market! http://www.aweber.com/?373860

Build high converting sales funnels with a few simple clicks of your mouse! https://bit.ly/484YV29

Join my Patreon for one-on-one coaching and help with your coding…https://www.patreon.com/c/TyronneRatcliff

Buy me a coffee ☕️https://buymeacoffee.com/tyronneratcliff

{ 0 comments }

JavaScript modules allow you to break your code into separate files, making it organized, reusable, and maintainable. This guide will walk you through the basics of ES Modules (ECMAScript Modules), the standard module system in JavaScript.


1. What are JavaScript Modules and Why Use Them?

Before modules, all JavaScript ran in a global scope, leading to a problem called “namespace pollution” where different parts of your code could accidentally overwrite variables in another file.

A module is simply a file that exports reusable pieces of code (functions, variables, classes) for other files to import.

Key Benefits:

  • Isolation: Variables and functions inside a module are private by default. Only what you explicitly export is visible outside.

  • Reusability: Write a function once and import it anywhere in your project.

  • Maintainability: Easier to understand, debug, and update small, focused files.

  • Dependency Management: Modules make it clear exactly what code is needed by another file.


2. Setting up ES Modules in HTML

To tell the browser to treat your JavaScript file as a module, you need to add type="module" to your script tag in your HTML file

<!DOCTYPE html>
<html>
<head>
    <title>JS Modules Demo</title>
</head>
<body>
    <h1>Check the Console!</h1>
    <script type="module" src="app.js"></script>
</body>
</html>

3. Named Exports and Imports

This is the most common way to share multiple pieces of code from a single module file.

A. Creating the Module (utils.js)

In your module file, use the export keyword before any variable, function, or class you want to make available.

// utils.js

// Exporting a function
export function add(a, b) {
    return a + b;
}

// Exporting a constant
export const API_KEY = '12345-abcde';

// You can also export them all at the end
function subtract(a, b) {
    return a - b;
}
export { subtract };

B. Importing and Using the Module (app.js)

In the file that needs the code, use the import keyword with curly braces {} to specify the exact names you want to import.

// app.js

import { add, API_KEY } from './utils.js';
import { subtract } from './utils.js'; // Can be imported separately or with others

const result = add(10, 5);
console.log(`10 + 5 = ${result}`); // Output: 10 + 5 = 15
console.log(`API Key: ${API_KEY}`); // Output: API Key: 12345-abcde

// You must include the file extension (e.g., .js) for browser imports!

Renaming Named Imports:

If you have a name conflict, you can rename an import using the as keyword:

// app.js
import { add as sum, subtract } from './utils.js';

console.log(sum(8, 2)); // 10

4. Default Exports and Imports

A module can only have one default export. This is typically used to export the main entity of the file (like a class or a primary function).

A. Creating the Default Export (User.js)

Use the export default keywords.

// User.js

export default class User {
    constructor(name) {
        this.name = name;
    }

    greet() {
        console.log(`Hello, my name is ${this.name}`);
    }
}

B. Importing the Default Export (app.js)

When importing a default export, you do not use curly braces, and you can give the imported item any name you like.

// app.js
import MyUserClass from './User.js'; // We named the import 'MyUserClass'

const user = new MyUserClass('Alice');
user.greet(); // Output: Hello, my name is Alice

💡 Pro Tip: You can mix default and named exports in the same file!


5. Dynamic Imports (The Next Level)

Standard imports are static, meaning they are loaded before the rest of the code runs.

Dynamic imports use the import() function syntax and allow you to load a module on demand (asynchronously). This is great for performance, as you can load large modules only when the user needs them.

// app.js

const button = document.getElementById('load-chart-btn');

button.addEventListener('click', async () => {
    // Dynamically load the 'chart-library.js' module
    try {
        const chartModule = await import('./chart-library.js');
        
        // Use the exported function
        chartModule.renderChart('data-container');
        console.log('Chart module loaded and rendered!');
    } catch (error) {
        console.error('Failed to load chart module:', error);
    }
});

Conclusion

ES Modules are the foundation of modern JavaScript. By using export and import correctly, you can create structured, efficient, and highly maintainable applications. Start splitting your larger projects into small, focused module files today!

Useful links below:

Let me & my team build you a money making website/blog for your business https://bit.ly/tnrwebsite_service

Get Bluehost hosting for as little as $1.99/month (save 75%)…https://bit.ly/3C1fZd2

Best email marketing automation solution on the market! http://www.aweber.com/?373860

Build high converting sales funnels with a few simple clicks of your mouse! https://bit.ly/484YV29

Join my Patreon for one-on-one coaching and help with your coding…https://www.patreon.com/c/TyronneRatcliff

Buy me a coffee ☕️https://buymeacoffee.com/tyronneratcliff

{ 0 comments }