Question

How to Clone a JavaScript Object Correctly

javascriptclonejavascript-objects

Question

I have a JavaScript object x, and I want to create a copy called y so that changing y does not affect x.

I noticed that copying objects can be tricky because JavaScript objects are assigned by reference. I am working with my own object created using an object literal, not with complex built-in objects.

How can I correctly clone a JavaScript object in JavaScript?

Short Answer

By the end of this page, you will understand why assigning one object to another does not create a copy in JavaScript, the difference between shallow and deep cloning, and the most common ways to clone objects safely using modern JavaScript.

Concept

In JavaScript, objects are reference types. That means when you do this:

const x = { name: "Alice" };
const y = x;

both x and y point to the same object in memory. If you change y.name, x.name changes too, because there is only one object.

To make an actual copy, you need to clone the object.

There are two main kinds of cloning:

Shallow clone

A shallow clone copies only the top-level properties.

const x = { name: "Alice", address: { city: "Paris" } };
const y = { ...x };

Now x and y are different objects, but nested objects like address are still shared.

Deep clone

A deep clone copies the object and all nested objects inside it.

const x = { name: "Alice", address: { city: "Paris" } };
const y = structuredClone(x);

Now changing y.address.city does not affect x.address.city.

Why this matters

Cloning matters when you want to:

  • avoid accidental mutation
  • keep original data unchanged
  • work safely with function inputs
  • update application state predictably
  • copy API data before modifying it

In real programs, choosing the wrong type of clone can create bugs that are hard to notice. A shallow clone may look correct until a nested property changes unexpectedly.

Mental Model

Think of an object like a house address written on a card.

  • A variable does not contain the whole house.
  • It contains the address of the house.
  • If you copy the card, both cards still point to the same house.
const x = { color: "blue" };
const y = x;

x and y are two cards with the same address.

If you paint the house through y, the house seen through x is also changed.

A shallow clone is like building a new house but reusing some of the furniture from the old house.

A deep clone is like building a new house and also making brand-new copies of all the furniture inside it.

Take Quiz

Syntax and Examples

Common ways to clone an object

1. Shallow clone with spread syntax

const original = { name: "Alice", age: 25 };
const copy = { ...original };

copy.name = "Bob";

console.log(original.name); // Alice
console.log(copy.name); // Bob

This works well for simple, flat objects.

2. Shallow clone with Object.assign()

const original = { name: "Alice", age: 25 };
const copy = Object.assign({}, original);

copy.age = 30;

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

This is similar to spread syntax for many common cases.

3. Deep clone with structuredClone()

const original = {
  name: "Alice",
  address: { city: "Paris" }
};

const copy = structuredClone(original);
copy.address.city = "London";

console.log(original.address.city); // Paris
console.log(copy.address.city); // London

Use this when nested objects must be copied too.

4. JSON-based cloning for simple data only

const original = {
  name: "Alice",
  address: { city: "Paris" }
};

const copy = JSON.parse(JSON.stringify(original));

This can deep copy simple JSON-safe data, but it does not handle everything correctly.

It can break or remove values such as:

  • undefined
  • functions
  • Date
  • Map
  • Set
  • circular references

Which one should you use?

  • Use { ...obj } for a quick shallow copy of a plain object.
  • Use Object.assign({}, obj) for another shallow-copy option.
  • Use structuredClone(obj) for deep cloning when supported and appropriate.
  • Avoid JSON.parse(JSON.stringify(obj)) unless the data is simple and JSON-safe.

Step by Step Execution

Consider this example:

const x = {
  user: "Sam",
  settings: {
    theme: "dark"
  }
};

const y = { ...x };
y.settings.theme = "light";

console.log(x.settings.theme);
console.log(y.settings.theme);

Step by step

1. Create x

const x = {
  user: "Sam",
  settings: {
    theme: "dark"
  }
};

x points to an object with two properties:

  • user → a string
  • settings → another object

2. Create y using spread syntax

const y = { ...x };

This creates a new top-level object.

So now:

  • y is not the same object as x
  • but y.settings still points to the same nested object as x.settings

3. Change a nested property

y.settings.theme = "light";

Because y.settings and x.settings refer to the same nested object, this change affects both.

4. Print the results

console.log(x.settings.theme); // light
console.log(y.settings.theme); // light

Even though x and y are separate top-level objects, the nested settings object was shared.

Deep clone version

const x = {
  user: "Sam",
  settings: {
    theme: "dark"
  }
};

const y = structuredClone(x);
y.settings.theme = "light";

console.log(x.settings.theme); // dark
console.log(y.settings.theme); // light

Now every nested level is copied, so changing y does not affect x.

Real World Use Cases

Object cloning appears in many everyday JavaScript tasks.

Updating UI state

Frameworks and state management patterns often rely on creating copies instead of mutating existing objects.

const state = { count: 1 };
const nextState = { ...state, count: 2 };

Preparing API data

You may want to copy server data before transforming it.

const userFromApi = { name: "Ana", active: true };
const editableUser = { ...userFromApi };

Function safety

If a function should not change its input, clone the object first.

function normalizeUser(user) {
  const copy = { ...user };
  copy.name = copy.name.trim();
  return copy;
}

Data processing pipelines

When processing lists of records, cloning helps preserve original data.

const updatedProducts = products.map(product => ({
  ...product,
  inStock: true
}));

Form editing

A form often uses a copied object so the original data stays unchanged until save.

Take Quiz

Real Codebase Usage

In real projects, developers rarely clone objects just for the sake of cloning. They clone objects to support safer patterns.

Immutable updates

A common pattern is to return a new object instead of changing the old one.

function updateProfile(profile, newEmail) {
  return { ...profile, email: newEmail };
}

Nested updates

When nested data is involved, developers often clone each level they are updating.

const updatedUser = {
  ...user,
  settings: {
    ...user.settings,
    theme: "light"
  }
};

This avoids unwanted shared references.

Guarding function inputs

Some functions clone inputs when they must safely transform data without side effects.

function prepareOptions(options = {}) {
  return {
    ...options,
    retry: options.retry ?? 3
  };
}

Configuration merging

Spread syntax is often used to combine defaults with custom options.

const finalConfig = {
  ...defaultConfig,
  ...userConfig
};

Error-safe transformations

When working with external data, developers often clone before validation or normalization so the original response remains available for debugging.

Common Mistakes

1. Thinking assignment creates a copy

const a = { value: 1 };
const b = a;
b.value = 2;

console.log(a.value); // 2

b = a does not clone the object. It copies the reference.

2. Using a shallow clone for nested objects

const a = { nested: { value: 1 } };
const b = { ...a };

b.nested.value = 2;
console.log(a.nested.value); // 2

Avoid this by using deep cloning when nested data must be independent.

3. Relying on JSON cloning for all data

Broken example:

const a = {
  createdAt: new Date(),
  greet: () => "hi",
  missing: undefined
};

const b = JSON.parse(JSON.stringify(a));
console.log(b);

Problems:

  • Date becomes a string
  • functions are removed
  • undefined is removed

4. Forgetting that arrays are also objects

const a = [1, 2, 3];
const b = a;
b.push(4);

console.log(a); // [1, 2, 3, 4]

Clone arrays too when needed:

const b = [...a];

5. Deep cloning when a shallow clone is enough

Deep cloning can be unnecessary and more expensive. If you only need to change top-level properties, a shallow clone is usually enough.

6. Mutating after cloning only the first level

const settings = {
  ui: {
    theme: "dark"
  }
};

const copy = { ...settings };
copy.ui.theme = "light";

This still mutates shared nested data. Clone the nested level too if needed.

Comparisons

Object cloning approaches

ApproachClone typeGood forLimitations
const y = xNo cloneSharing the same object intentionallyChanges affect both variables
{ ...x }ShallowPlain objects, top-level updatesNested objects are shared
Object.assign({}, x)ShallowSimilar to spread syntaxNested objects are shared
structuredClone(x)DeepNested data, safer full copiesEnvironment support must exist; not for every special case
JSON.parse(JSON.stringify(x))Deep-ishSimple JSON dataLoses unsupported values and fails on circular references

Spread vs Object.assign()

FeatureSpread syntaxObject.assign()
ReadabilityUsually easier to readSlightly more verbose
Shallow cloneYesYes
Merge objectsYesYes
Common modern useVery commonStill common

Shallow clone vs deep clone

TypeCopies top levelCopies nested objectsBest use
Shallow cloneYesNoFlat objects or controlled nested updates
Deep cloneYesYesFully independent copies of nested data
Take Quiz

Cheat Sheet

Quick reference

Assignment does not clone

const y = x;
  • x and y point to the same object

Shallow clone

const y = { ...x };
const y2 = Object.assign({}, x);
  • copies only top-level properties
  • nested objects remain shared

Deep clone

const y = structuredClone(x);
  • copies nested objects too
  • best modern built-in option for many cases

JSON clone

const y = JSON.parse(JSON.stringify(x));
  • works only for simple JSON-safe data
  • loses functions, undefined, and special object types

Nested update pattern

const updated = {
  ...user,
  settings: {
    ...user.settings,
    theme: "light"
  }
};

Rule of thumb

  • flat object: use spread
  • nested object and full independence needed: use structuredClone()
  • avoid plain assignment if you need a real copy

FAQ

Why does const y = x not copy an object in JavaScript?

Because objects are stored by reference. The variable gets a reference to the same object, not a separate duplicate.

What is the easiest way to clone a simple object in JavaScript?

For a plain flat object, use spread syntax:

const copy = { ...original };

Does spread syntax create a deep copy?

No. It creates a shallow copy only. Nested objects and arrays are still shared.

When should I use structuredClone()?

Use it when you need a deep copy of nested data and your environment supports it.

Is JSON.parse(JSON.stringify(obj)) a good cloning method?

Only for simple JSON-style data. It breaks or removes some values, so it is not a general-purpose cloning solution.

How do I clone a nested object without sharing inner properties?

Use structuredClone() or manually clone each nested level you need to update.

Are arrays cloned the same way as objects?

They follow the same reference rules. Use:

const copy = [...array];

for a shallow array clone.

Take Quiz

Mini Project

Description

Build a small profile editor that copies a user object before making changes. This project demonstrates the difference between shallow and deep cloning, especially when nested settings are involved.

Goal

Create a program that safely edits a copied user profile without changing the original object.

Requirements

[ "Create a user object with at least one nested object property.", "Make one shallow copy and one deep copy of the user object.", "Modify nested data in each copy.", "Print the original object and both copies to compare the results.", "Use modern JavaScript syntax." ]

Take Quiz

Keep learning

Related questions

View more