Falytom logoFALYTOM
Games
ToolsUI ComponentsServicesProductsAbout
LoginSign Up
menu
  1. Home
  2. /Web Development
  3. /Javascript
  4. /Spread Operator Object Cloning
Your Progress0%
0 of 61 completed

JavaScript Topics

Getting Started

  • What is JavaScript?
  • JavaScript vs Other Languages
  • Setting Up Your JavaScript Environment
  • Developer Console and Debugging Basics

JavaScript Fundamentals

  • Variables (var, let, const)
  • Data Types and Type Checking
  • Comments and Code Organization
  • String Methods and Template Literals
  • Type Conversion and Coercion
  • Operators (Arithmetic, Comparison, Logical)

Control Flow

  • If/Else Statements
  • Switch Statements
  • Ternary Operator
  • Truthy and Falsy Values
  • Logical Operators and Short-Circuiting

Loops and Iteration

  • For Loops
  • While and Do-While Loops
  • For...of and For...in Loops
  • Break and Continue Statements

Functions

  • Function Declarations and Expressions
  • Arrow Functions
  • Function Parameters and Arguments
  • Return Statements and Values
  • Scope and Closures
  • Higher-Order Functions and Callbacks

Arrays

  • Array Basics and Creation
  • Array Methods: Adding and Removing Elements
  • Array Iteration Methods (forEach, map, filter)
  • Array Methods: find, some, every, reduce
  • Sorting, Reversing, and Array Transformation

Objects

  • Object Basics and Properties
  • Object Methods and 'this' Keyword
  • Object Destructuring
  • Object.keys, values, entries
  • Spread Operator and Object Cloning

DOM Manipulation

  • Introduction to the DOM
  • Selecting Elements (querySelector, getElementById)
  • Modifying Elements (textContent, innerHTML, style)
  • Creating and Removing Elements
  • Event Listeners and Event Handling
  • Event Object and Event Delegation

Asynchronous JavaScript

  • Understanding Asynchronous Code
  • setTimeout and setInterval
  • Callbacks and Callback Hell
  • Promises and Promise Chaining
  • Async/Await

Error Handling

  • Try, Catch, Finally
  • Throwing Custom Errors

Modern JavaScript Features

  • ES6+ Overview
  • Modules (import/export)
  • Optional Chaining and Nullish Coalescing
  • Rest and Spread Operators

Working with Data

  • JSON (Parse and Stringify)
  • Fetch API and HTTP Requests
  • Working with Local Storage

Advanced Concepts

  • Classes and Object-Oriented Programming
  • Array and Object Advanced Patterns
  • Regular Expressions Basics

Best Practices & Real-World Application

  • JavaScript Best Practices
  • Debugging Techniques and Tools
  • Building a Complete Interactive Project

Spread Operator and Object Cloning

Copying, merging, and understanding object references

The spread operator (...) is a powerful ES6 feature for working with objects. It provides a clean syntax for copying and merging objects, making your code more concise and readable. However, understanding the difference between shallow and deep copying is crucial to avoid bugs with nested objects. Let's master object cloning and the spread operator!

Understanding Object References

Before learning about cloning, it's important to understand how object references work in JavaScript.

JAVASCRIPT
// Objects are stored by reference
let user1 = {
  name: "Alice",
  age: 25
};

// Assignment creates a reference, NOT a copy
let user2 = user1;

console.log(user1);  // { name: "Alice", age: 25 }
console.log(user2);  // { name: "Alice", age: 25 }

// Modify user2
user2.age = 30;

// Both are affected (same object!)
console.log(user1.age);  // 30
console.log(user2.age);  // 30

// They reference the same object
console.log(user1 === user2);  // true

// Primitive values work differently
let a = 5;
let b = a;  // Copy the value
b = 10;

console.log(a);  // 5 (unchanged)
console.log(b);  // 10

Key Concept:

When you assign an object to a variable, you're storing a reference to the object, not the object itself. This means multiple variables can point to the same object in memory.

Spread Operator for Objects

The spread operator (...) creates a shallow copy of an object by spreading its properties into a new object.

Basic Copying

JAVASCRIPT
let original = {
  name: "Alice",
  age: 25,
  city: "NYC"
};

// Create a copy using spread operator
let copy = { ...original };

console.log(original);  // { name: "Alice", age: 25, city: "NYC" }
console.log(copy);      // { name: "Alice", age: 25, city: "NYC" }

// They are different objects
console.log(original === copy);  // false

// Modify copy
copy.age = 30;

console.log(original.age);  // 25 (unchanged!)
console.log(copy.age);      // 30

// Original is not affected
console.log(original);  // { name: "Alice", age: 25, city: "NYC" }
console.log(copy);      // { name: "Alice", age: 30, city: "NYC" }

Spread creates an independent copy

Reference (Not a Copy)

// Without spread operator
let original = {
  name: "Alice",
  age: 25
};

// Reference, NOT copy
let copy = original;

copy.age = 30;

console.log(original.age);  // 30 (affected!)
console.log(copy.age);      // 30

// Same object
console.log(original === copy);  // true
Output:
Not run yet...

Spread Operator (Real Copy)

// With spread operator
let original = {
  name: "Alice",
  age: 25
};

// Create actual copy
let copy = { ...original };

copy.age = 30;

console.log(original.age);  // 25 (unchanged)
console.log(copy.age);      // 30

// Different objects
console.log(original === copy);  // false
Output:
Not run yet...

Merging Objects

The spread operator is perfect for merging multiple objects together.

Basic Merging

JAVASCRIPT
let defaults = {
  theme: "light",
  notifications: true,
  language: "en"
};

let userPreferences = {
  theme: "dark",
  fontSize: 14
};

// Merge objects (later properties override earlier ones)
let settings = { ...defaults, ...userPreferences };

console.log(settings);
// {
//   theme: "dark",           // Overridden by userPreferences
//   notifications: true,     // From defaults
//   language: "en",          // From defaults
//   fontSize: 14             // From userPreferences
// }

// Order matters!
let settings2 = { ...userPreferences, ...defaults };
console.log(settings2);
// {
//   theme: "light",          // defaults override userPreferences
//   fontSize: 14,
//   notifications: true,
//   language: "en"
// }

Merging Multiple Objects

JAVASCRIPT
let obj1 = { a: 1, b: 2 };
let obj2 = { c: 3, d: 4 };
let obj3 = { e: 5, f: 6 };

// Merge all three
let merged = { ...obj1, ...obj2, ...obj3 };
console.log(merged);
// { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 }

// Add new properties while merging
let extended = {
  ...obj1,
  ...obj2,
  g: 7,
  h: 8
};
console.log(extended);
// { a: 1, b: 2, c: 3, d: 4, g: 7, h: 8 }

Overriding Properties

JAVASCRIPT
let user = {
  name: "Alice",
  age: 25,
  email: "alice@test.com"
};

// Update specific properties
let updatedUser = {
  ...user,
  age: 26,           // Override age
  city: "NYC"        // Add new property
};

console.log(updatedUser);
// {
//   name: "Alice",
//   age: 26,              // Updated
//   email: "alice@test.com",
//   city: "NYC"           // Added
// }

// Original unchanged
console.log(user);
// { name: "Alice", age: 25, email: "alice@test.com" }

// Practical: Add timestamp to object
let data = { value: 100, type: "payment" };
let withTimestamp = {
  ...data,
  timestamp: new Date().toISOString()
};
console.log(withTimestamp);

Shallow Copy vs Deep Copy

The spread operator creates a shallow copy—nested objects are still referenced, not copied.

The Problem with Shallow Copies

JAVASCRIPT
let user = {
  name: "Alice",
  age: 25,
  address: {
    city: "NYC",
    country: "USA"
  }
};

// Shallow copy
let copy = { ...user };

// Modify top-level property (works as expected)
copy.name = "Bob";
console.log(user.name);  // "Alice" (unchanged)
console.log(copy.name);  // "Bob"

// Modify nested object (problem!)
copy.address.city = "LA";

console.log(user.address.city);  // "LA" (changed!)
console.log(copy.address.city);  // "LA"

// Why? Nested objects are referenced, not copied
console.log(user.address === copy.address);  // true (same object!)

// Visual representation:
// user.address ──┐
//                ├──> { city: "LA", country: "USA" }
// copy.address ──┘

Warning:

Shallow copies only copy the first level of properties. Nested objects, arrays, and other reference types are still shared between the original and the copy. This can lead to unexpected bugs!

Deep Copying Methods

JAVASCRIPT
let user = {
  name: "Alice",
  age: 25,
  address: {
    city: "NYC",
    country: "USA"
  },
  hobbies: ["reading", "coding"]
};

// Method 1: JSON parse/stringify (simple but limited)
let deepCopy1 = JSON.parse(JSON.stringify(user));

deepCopy1.address.city = "LA";
deepCopy1.hobbies.push("gaming");

console.log(user.address.city);    // "NYC" (unchanged!)
console.log(user.hobbies.length);  // 2 (unchanged!)

// Limitations of JSON method:
// - Loses functions
// - Loses undefined values
// - Loses Dates (converts to strings)
// - Can't handle circular references

let withFunction = {
  name: "Alice",
  greet: function() { return "Hello"; }
};

let jsonCopy = JSON.parse(JSON.stringify(withFunction));
console.log(jsonCopy);  // { name: "Alice" } - greet is lost!

// Method 2: structuredClone() (modern, recommended)
let user2 = {
  name: "Bob",
  address: {
    city: "NYC"
  }
};

let deepCopy2 = structuredClone(user2);

deepCopy2.address.city = "LA";
console.log(user2.address.city);  // "NYC" (unchanged!)

// structuredClone handles more types correctly
// But still can't clone functions

// Method 3: Manual deep copy function
function deepClone(obj) {
  // Handle null and primitives
  if (obj === null || typeof obj !== "object") {
    return obj;
  }
  
  // Handle arrays
  if (Array.isArray(obj)) {
    return obj.map(item => deepClone(item));
  }
  
  // Handle objects
  let cloned = {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      cloned[key] = deepClone(obj[key]);
    }
  }
  return cloned;
}

let user3 = {
  name: "Charlie",
  address: { city: "NYC" },
  hobbies: ["reading"]
};

let deepCopy3 = deepClone(user3);
deepCopy3.address.city = "LA";
deepCopy3.hobbies.push("gaming");

console.log(user3.address.city);    // "NYC"
console.log(user3.hobbies.length);  // 1

Object.assign() Alternative

Before the spread operator, Object.assign() was the standard way to copy and merge objects. It works similarly but with different syntax.

JAVASCRIPT
let original = {
  name: "Alice",
  age: 25
};

// Using Object.assign() - old way
let copy1 = Object.assign({}, original);

// Using spread operator - modern way (preferred)
let copy2 = { ...original };

console.log(copy1);  // { name: "Alice", age: 25 }
console.log(copy2);  // { name: "Alice", age: 25 }

// Merging with Object.assign()
let defaults = { theme: "light", size: "medium" };
let custom = { theme: "dark" };

let merged1 = Object.assign({}, defaults, custom);
// { theme: "dark", size: "medium" }

// Same with spread (cleaner)
let merged2 = { ...defaults, ...custom };
// { theme: "dark", size: "medium" }

// Object.assign modifies first argument
let target = { a: 1 };
Object.assign(target, { b: 2 });
console.log(target);  // { a: 1, b: 2 } (modified!)

// Spread always creates new object
let obj = { a: 1 };
let newObj = { ...obj, b: 2 };
console.log(obj);     // { a: 1 } (unchanged)
console.log(newObj);  // { a: 1, b: 2 }

Best Practice: Use the spread operator over Object.assign() for cleaner, more readable code. The spread operator is the modern standard.

Practical Patterns

Pattern 1: Updating State Immutably

JAVASCRIPT
// Immutable updates (used in React, Redux, etc.)
let state = {
  user: {
    name: "Alice",
    age: 25
  },
  settings: {
    theme: "light"
  }
};

// Update nested property immutably
let newState = {
  ...state,
  user: {
    ...state.user,
    age: 26  // Update age
  }
};

console.log(state.user.age);     // 25 (original unchanged)
console.log(newState.user.age);  // 26

// Add property to nested object
let stateWithCity = {
  ...state,
  user: {
    ...state.user,
    city: "NYC"
  }
};

console.log(stateWithCity);
// {
//   user: { name: "Alice", age: 25, city: "NYC" },
//   settings: { theme: "light" }
// }

Pattern 2: Conditional Properties

JAVASCRIPT
function createUser(name, email, isAdmin) {
  return {
    name,
    email,
    createdAt: new Date(),
    // Conditionally add admin property
    ...(isAdmin && { role: "admin", permissions: ["read", "write", "delete"] })
  };
}

let regularUser = createUser("Alice", "alice@test.com", false);
console.log(regularUser);
// { name: "Alice", email: "alice@test.com", createdAt: ... }

let adminUser = createUser("Bob", "bob@test.com", true);
console.log(adminUser);
// {
//   name: "Bob",
//   email: "bob@test.com",
//   createdAt: ...,
//   role: "admin",
//   permissions: ["read", "write", "delete"]
// }

// Multiple conditional properties
function createProduct(name, price, options = {}) {
  return {
    name,
    price,
    ...(options.featured && { featured: true }),
    ...(options.discount && { discount: options.discount }),
    ...(options.tags && { tags: options.tags })
  };
}

let product1 = createProduct("Laptop", 1000);
console.log(product1);  // { name: "Laptop", price: 1000 }

let product2 = createProduct("Mouse", 25, {
  featured: true,
  discount: 10,
  tags: ["electronics", "accessories"]
});
console.log(product2);
// {
//   name: "Mouse",
//   price: 25,
//   featured: true,
//   discount: 10,
//   tags: ["electronics", "accessories"]
// }

Pattern 3: Removing Properties

JAVASCRIPT
let user = {
  name: "Alice",
  age: 25,
  email: "alice@test.com",
  password: "secret123",
  role: "admin"
};

// Remove password using destructuring and rest
let { password, ...safeUser } = user;

console.log(safeUser);
// { name: "Alice", age: 25, email: "alice@test.com", role: "admin" }

// Remove multiple properties
let { password: pwd, role, ...publicUser } = user;

console.log(publicUser);
// { name: "Alice", age: 25, email: "alice@test.com" }

// Function to remove sensitive data
function sanitizeUser(user) {
  let { password, privateKey, ...safe } = user;
  return safe;
}

let rawUser = {
  name: "Bob",
  email: "bob@test.com",
  password: "secret",
  privateKey: "key123"
};

console.log(sanitizeUser(rawUser));
// { name: "Bob", email: "bob@test.com" }

Pattern 4: Default Options with Override

JAVASCRIPT
function fetchData(url, options = {}) {
  // Default options
  let defaultOptions = {
    method: "GET",
    headers: {
      "Content-Type": "application/json"
    },
    timeout: 5000
  };
  
  // Merge with user options (user options override defaults)
  let finalOptions = {
    ...defaultOptions,
    ...options,
    // Deep merge headers
    headers: {
      ...defaultOptions.headers,
      ...options.headers
    }
  };
  
  console.log(`Fetching ${url} with:`, finalOptions);
  return finalOptions;
}

// Use defaults
fetchData("/api/users");
// { method: "GET", headers: { "Content-Type": "application/json" }, timeout: 5000 }

// Override some options
fetchData("/api/data", {
  method: "POST",
  timeout: 10000,
  headers: {
    "Authorization": "Bearer token123"
  }
});
// {
//   method: "POST",
//   headers: {
//     "Content-Type": "application/json",
//     "Authorization": "Bearer token123"
//   },
//   timeout: 10000
// }

Practical Examples

Example 1: Configuration Manager

JAVASCRIPT
class ConfigManager {
  constructor(defaults = {}) {
    this.defaults = defaults;
    this.config = { ...defaults };
  }
  
  set(options) {
    // Merge with existing config
    this.config = {
      ...this.config,
      ...options
    };
  }
  
  get(key) {
    return this.config[key];
  }
  
  reset() {
    // Reset to defaults
    this.config = { ...this.defaults };
  }
  
  getAll() {
    // Return copy of config
    return { ...this.config };
  }
}

let config = new ConfigManager({
  theme: "light",
  language: "en",
  notifications: true
});

console.log("Initial:", config.getAll());

config.set({ theme: "dark", fontSize: 14 });
console.log("Updated:", config.getAll());

config.reset();
console.log("Reset:", config.getAll());

Example 2: Form Data Handler

JAVASCRIPT
function processFormData(formData, validations = {}) {
  // Default form structure
  let defaultForm = {
    submitted: false,
    errors: {},
    touched: {},
    values: {}
  };
  
  // Merge with provided data
  let form = {
    ...defaultForm,
    ...formData,
    // Deep merge values
    values: {
      ...defaultForm.values,
      ...formData.values
    }
  };
  
  // Apply validations
  Object.keys(validations).forEach(field => {
    if (validations[field](form.values[field]) === false) {
      form.errors[field] = `Invalid ${field}`;
    }
  });
  
  return form;
}

let formData = {
  values: {
    email: "alice@test.com",
    age: 25
  },
  touched: {
    email: true
  }
};

let validations = {
  email: value => value && value.includes("@"),
  age: value => value >= 18
};

let result = processFormData(formData, validations);
console.log(result);

Spread Operator and Cloning Practice

Experiment with object copying and merging

Output:
Click "Run" to execute your code...
💡 Tip: Use console.log() to see your output in the console above.

Key Takeaways

  • Use spread operator { ...obj } to copy objects
  • Spread creates shallow copies—nested objects are referenced
  • Merge objects with { ...obj1, ...obj2 }
  • Later properties override earlier ones in merges
  • Use structuredClone() or JSON methods for deep copies
  • Assignment (=) creates references, not copies
  • Spread operator is preferred over Object.assign()
  • Use destructuring with rest to remove properties
  • Spread enables immutable updates (important for React/Redux)
  • Always copy objects when you don't want to modify the original

What's Next?

Congratulations! You've completed the Objects section and now have a comprehensive understanding of JavaScript objects—from basic properties to advanced cloning and merging techniques. Objects are fundamental to JavaScript, and you now have the skills to work with them effectively!

You've now completed 36 out of 62 JavaScript tutorial pages, covering Introduction, Variables & Data Types, Operators, Control Flow, Loops, Functions, Arrays, and Objects. You're making excellent progress through this comprehensive JavaScript course!

💪 Practice Challenge:

Before moving on, try creating:

  1. A function that deep clones an object with nested properties
  2. Merge multiple configuration objects with proper precedence
  3. Update a nested object property immutably (without mutating original)
  4. Create a function that removes specified properties from an object
  5. Build a state management system that uses immutable updates

Test Your Understanding

Question 1 / 4

What does the spread operator (...) do with objects?

Score: 0 / 0

Mastering JavaScript object cloning and spread operator! 📋

Previous
Object.keys, values, entries
Next
Introduction to the DOM

Continue Learning JavaScript

Join 2,000+ developers mastering JavaScript. New lessons weekly - 100% FREE.

You might also like

UI Components

Ready-made components for your projects

Developer Tools

Boost productivity with handy generators

HTML Game

Learn HTML concepts through interactive gameplay

Join Our Web Development Training Program

Master frontend & backend development with hands-on projects.

JavaScript Tutorials

0 of 61 completed

Your Progress0%

Topics

Getting Started

  • What is JavaScript?
  • JavaScript vs Other Languages
  • Setting Up Your JavaScript Environment
  • Developer Console and Debugging Basics

JavaScript Fundamentals

  • Variables (var, let, const)
  • Data Types and Type Checking
  • Comments and Code Organization
  • String Methods and Template Literals
  • Type Conversion and Coercion
  • Operators (Arithmetic, Comparison, Logical)

Control Flow

  • If/Else Statements
  • Switch Statements
  • Ternary Operator
  • Truthy and Falsy Values
  • Logical Operators and Short-Circuiting

Loops and Iteration

  • For Loops
  • While and Do-While Loops
  • For...of and For...in Loops
  • Break and Continue Statements

Functions

  • Function Declarations and Expressions
  • Arrow Functions
  • Function Parameters and Arguments
  • Return Statements and Values
  • Scope and Closures
  • Higher-Order Functions and Callbacks

Arrays

  • Array Basics and Creation
  • Array Methods: Adding and Removing Elements
  • Array Iteration Methods (forEach, map, filter)
  • Array Methods: find, some, every, reduce
  • Sorting, Reversing, and Array Transformation

Objects

  • Object Basics and Properties
  • Object Methods and 'this' Keyword
  • Object Destructuring
  • Object.keys, values, entries
  • Spread Operator and Object Cloning

DOM Manipulation

  • Introduction to the DOM
  • Selecting Elements (querySelector, getElementById)
  • Modifying Elements (textContent, innerHTML, style)
  • Creating and Removing Elements
  • Event Listeners and Event Handling
  • Event Object and Event Delegation

Asynchronous JavaScript

  • Understanding Asynchronous Code
  • setTimeout and setInterval
  • Callbacks and Callback Hell
  • Promises and Promise Chaining
  • Async/Await

Error Handling

  • Try, Catch, Finally
  • Throwing Custom Errors

Modern JavaScript Features

  • ES6+ Overview
  • Modules (import/export)
  • Optional Chaining and Nullish Coalescing
  • Rest and Spread Operators

Working with Data

  • JSON (Parse and Stringify)
  • Fetch API and HTTP Requests
  • Working with Local Storage

Advanced Concepts

  • Classes and Object-Oriented Programming
  • Array and Object Advanced Patterns
  • Regular Expressions Basics

Best Practices & Real-World Application

  • JavaScript Best Practices
  • Debugging Techniques and Tools
  • Building a Complete Interactive Project
Falytom logoFALYTOM

Learn technologies like HTML, CSS, JavaScript, React, NodeJS and more through interactive games, tutorials, components and free tools. Transform your businesses with AI chatbots, SEO-optimized websites, and professional development services.

© 2025 Tomilola Group
  • Facebook logo
  • Twitter logo
  • Instagram logo
  • LinkedIn logo
  • GitHub logo
  • YouTube logo