How do you clone an object or array in JavaScript?
Advertisement
🧩 Scenario
Architecture Walkthrough
How JavaScript Stores Reference Types
Primitive values like numbers, strings, and booleans are stored directly in memory. When you assign a primitive to a new variable, you get an independent copy. Objects and arrays are stored as references: the variable holds a pointer to a location in memory, not the actual data. When you assign an object to another variable without cloning, both variables point to the same memory location. Changing one changes the other.
This is why cloning is necessary whenever you want to produce an independent copy of an object or array. Without an explicit clone, any modification to the "copy" will silently affect the original.
Shallow Copies: Spread, Object.assign, and Array.from
Shallow copying creates a new top-level object or array, but any nested values that are reference types still share the same memory address as the original. The spread operator ({...obj} or [...arr]), Object.assign({}, obj), and Array.from(arr) all produce shallow copies.
For flat structures (objects or arrays that contain only primitives), a shallow copy is sufficient and is the most performant option. The problem arises when your data contains nested objects or arrays. Modifying a nested property in the copy will modify it in the original as well, because both point to the same nested object in memory.
Deep Copies: JSON, structuredClone, and Libraries
A deep copy recursively copies every value, including nested objects and arrays, so that no part of the clone shares a reference with the original. The oldest approach is JSON.parse(JSON.stringify(obj)), which serializes the object to a JSON string and then parses it back. This works well for simple plain objects and arrays containing only JSON-compatible types.
The JSON approach silently drops undefined values, converts Date objects to strings, loses functions entirely, and throws on circular references. The modern native alternative is structuredClone(obj), available in Node.js 17+ and all modern browsers. It handles Date, Map, Set, ArrayBuffer, and circular references correctly, making it the preferred choice for deep cloning in most production scenarios. For very complex cases, libraries like Lodash provide cloneDeep.
Key Code Explained
const original = {
name: 'Ghazi',
skills: ['React', 'Node'],
address: { city: 'Lahore' },
};
// Shallow copy: top-level properties are independent
const shallow = { ...original };
shallow.name = 'Ali'; // original.name is still 'Ghazi'
shallow.address.city = 'Karachi'; // original.address.city is now 'Karachi' too
// Deep copy with structuredClone: fully independent
const deep = structuredClone(original);
deep.address.city = 'Karachi'; // original.address.city remains 'Lahore'
// JSON approach: works for plain data, but loses non-JSON types
const jsonClone = JSON.parse(JSON.stringify(original));
// JSON approach failure cases
const tricky = {
date: new Date(), // becomes a string in the clone
fn: () => 'hello', // silently dropped
value: undefined, // silently dropped
};
const brokenClone = JSON.parse(JSON.stringify(tricky));
// brokenClone.date is a string, brokenClone.fn is undefined, brokenClone.value is undefined
The shallow copy example shows exactly where the reference sharing happens: top-level primitive properties are independent, but nested objects are shared. This is the most common source of confusion and bugs when cloning in JavaScript.
Tradeoffs
| Approach | Pro | Con |
|---|---|---|
| Spread / Object.assign | Fast, zero dependencies, sufficient for flat data | Nested references are shared, not truly independent |
| JSON.parse/JSON.stringify | Works without any library, familiar pattern | Drops functions and undefined, mangles Dates, fails on circular refs |
| structuredClone | Native, handles Dates, Sets, Maps, circular refs | Not available in older environments, cannot clone functions |
| Lodash cloneDeep | Handles virtually all cases | Adds a dependency, slower for large objects |
What Interviewers Actually Check
- Whether you can distinguish a shallow copy from a deep copy using a concrete nested example
- Whether you know the limitations of the JSON round-trip approach and can name specific failure cases
- Whether you know
structuredCloneexists and when to use it over JSON - Whether you understand why immutability matters in state management contexts like React
- Whether you can correctly predict the behavior of spread on a nested object
- Whether you reach for the simplest tool (shallow copy) when the data is flat, rather than always deep cloning
Follow-Up Questions
- How does React detect state changes, and why does mutating a cloned object that still shares nested references cause bugs in a React component?
- What would happen if you called
structuredCloneon an object containing a function or a class instance? - How would you write a test to verify that a cloning utility produces a truly independent deep copy?
- If you need to clone a very large nested object hundreds of times per second for a real-time feature, what performance concerns would you raise?
- A PR you are reviewing uses
JSON.parse(JSON.stringify(data))to clone API response data. What questions would you ask before approving it?
Common Candidate Mistakes
- Using spread or
Object.assignand assuming nested objects are fully cloned when they are only shallow copied - Using
JSON.parse(JSON.stringify())on data that contains functions,undefined,Dateobjects, or circular references, without knowing what gets dropped or mutated - Modifying a cloned array element that is itself an object, and being surprised that the original was changed
- Not knowing that
structuredCloneexists as a built-in native alternative to the JSON approach - Treating
Array.fromorsliceas deep clones when they produce shallow copies exactly like spread
Interview Readiness Checklist
Before you leave this question, make sure you can answer:
- Can you explain the difference between a shallow copy and a deep copy with a concrete nested object example?
- Can you list at least three methods for creating a shallow copy of an object or array?
- Can you explain why
JSON.parse/JSON.stringifyfails with functions,Dateobjects, and circular references? - Can you describe when
structuredCloneis preferable to the JSON approach? - Can you explain why immutability matters when managing state in React or Redux?
- Can you identify which cloning strategy to reach for given a specific data shape?
Summary
Cloning in JavaScript requires understanding how reference types are stored. Primitives copy by value, while objects and arrays copy by reference. Without an explicit clone, two variables pointing to the same object will both reflect any modification made through either one.
For flat data, a shallow copy using spread or Object.assign is sufficient and performant. For nested data, you need a deep clone. The modern native choice is structuredClone, which handles Date, Map, Set, and circular references correctly. The older JSON approach works for simple plain objects but silently drops or transforms several data types, making it a footgun in production codebases.
The most important interview signal on this question is not knowing every method by name, but understanding the trade-off between shallow and deep copies and being able to predict what breaks when the wrong approach is used on nested data.
Does spread operator create a deep copy?
No, it only creates a shallow copy — nested objects still reference the original.
Advertisement
Stay Updated
Get the latest frontend challenges, interview questions and tutorials delivered to your inbox.
Advertisement