JavaScript - Shallow Copy: A Beginner's Guide

Hello there, future JavaScript wizards! Today, we're going to embark on an exciting journey into the world of shallow copying in JavaScript. Don't worry if you're new to programming – I'll be your friendly guide, explaining everything step by step. So, grab a cup of coffee (or your favorite beverage), and let's dive in!

JavaScript - Shallow Copy

What is a Shallow Copy?

Before we get into the nitty-gritty of shallow copying, let's start with a simple analogy. Imagine you have a beautiful painting, and you want to make a copy of it. You have two options:

  1. Take a photograph of the painting (shallow copy)
  2. Recreate the entire painting from scratch (deep copy)

In JavaScript, a shallow copy is like taking that photograph. It creates a new object or array, but the elements inside are references to the same elements as the original.

How Shallow Copy Works

When you create a shallow copy:

  1. A new object or array is created
  2. The top-level properties are copied
  3. Nested objects or arrays are still referenced from the original

Let's see this in action with some code!

// Original object
let original = {
  name: "Alice",
  age: 30,
  hobbies: ["reading", "swimming"]
};

// Shallow copy
let shallowCopy = Object.assign({}, original);

// Modifying the copy
shallowCopy.name = "Bob";
shallowCopy.hobbies.push("coding");

console.log(original);
console.log(shallowCopy);

If you run this code, you'll see something interesting:

{name: "Alice", age: 30, hobbies: ["reading", "swimming", "coding"]}
{name: "Bob", age: 30, hobbies: ["reading", "swimming", "coding"]}

Notice how changing name only affected the copy, but modifying hobbies affected both objects. That's the essence of a shallow copy!

Deep Copy vs. Shallow Copy

Now that we understand shallow copy, let's compare it to its sibling, deep copy.

Feature Shallow Copy Deep Copy
New object creation Yes Yes
Copies top-level properties Yes Yes
Copies nested objects/arrays No (references original) Yes (creates new copies)
Performance Faster Slower
Memory usage Less More

When to Use Shallow Copy

Shallow copies are great when:

  1. You only need to modify top-level properties
  2. Performance is a concern
  3. You want to create a new reference to an object

When to Use Deep Copy

Deep copies are better when:

  1. You need to modify nested properties without affecting the original
  2. You want a completely independent copy of an object

Examples of Shallow Copy in JavaScript

Let's explore some common ways to create shallow copies in JavaScript!

1. Object.assign()

let original = { a: 1, b: { c: 2 } };
let copy = Object.assign({}, original);

copy.a = 5;
copy.b.c = 10;

console.log(original); // { a: 1, b: { c: 10 } }
console.log(copy);     // { a: 5, b: { c: 10 } }

Here, Object.assign() creates a shallow copy. Changing a only affects the copy, but changing b.c affects both objects because it's a nested property.

2. Spread Operator (...)

let fruits = ["apple", "banana", ["grape", "orange"]];
let fruitsCopy = [...fruits];

fruitsCopy[0] = "pear";
fruitsCopy[2].push("kiwi");

console.log(fruits);     // ["apple", "banana", ["grape", "orange", "kiwi"]]
console.log(fruitsCopy); // ["pear", "banana", ["grape", "orange", "kiwi"]]

The spread operator creates a shallow copy of the array. Modifying the first element only affects the copy, but adding to the nested array affects both.

3. Array.from()

let numbers = [1, 2, [3, 4]];
let numbersCopy = Array.from(numbers);

numbersCopy[0] = 10;
numbersCopy[2].push(5);

console.log(numbers);     // [1, 2, [3, 4, 5]]
console.log(numbersCopy); // [10, 2, [3, 4, 5]]

Array.from() also creates a shallow copy. The first-level elements are copied, but nested arrays are still referenced.

The Importance of Shallow Copy

You might be wondering, "Why do we need shallow copies at all?" Great question! Shallow copies are incredibly useful in many scenarios:

  1. Performance: Shallow copies are faster and use less memory than deep copies, making them ideal for large objects or frequent operations.

  2. Immutability: They help maintain immutability in your code, which is crucial for predictable state management in modern JavaScript frameworks.

  3. Avoiding Side Effects: Shallow copies allow you to modify an object without directly changing the original, reducing unexpected side effects in your code.

  4. React and Redux: In React and Redux applications, shallow copies are often used to trigger re-renders and update state without mutating the original data.

Here's a real-world example:

function updateUserProfile(user, newName) {
  // Create a shallow copy of the user object
  let updatedUser = Object.assign({}, user);

  // Update the name
  updatedUser.name = newName;

  return updatedUser;
}

let user = {
  name: "Alice",
  age: 30,
  address: {
    city: "Wonderland",
    street: "Rabbit Hole Lane"
  }
};

let updatedUser = updateUserProfile(user, "Alicia");

console.log(user);        // Original user object unchanged
console.log(updatedUser); // New object with updated name

In this example, we're updating a user's name without modifying the original object. This is a common pattern in state management and helps maintain data integrity.

Conclusion

Congratulations! You've just taken your first steps into the world of shallow copying in JavaScript. Remember, shallow copies are like taking a quick snapshot – they're fast and efficient, but they don't capture everything in full detail.

As you continue your JavaScript journey, you'll find plenty of situations where shallow copying comes in handy. It's a powerful tool in your programming toolkit, especially when working with complex data structures and state management.

Keep practicing, stay curious, and don't be afraid to experiment. Before you know it, you'll be creating and manipulating objects like a pro!

Happy coding, and may your copies always be as shallow (or deep) as you need them to be! ?

Credits: Image by storyset