A shallow copy occurs when you copy the reference of an object to a new variable. In this process, only the top-level properties are copied, while nested objects or arrays still reference the original memory location. This means that if you change the nested properties in one object, those changes will reflect in the other because they share the same memory reference.
How Shallow Copy Works
A shallow copy is created using methods like the spread operator ({ ...obj }) or Object.assign(). In contrast, using the assignment operator (=) only copies the reference, not the actual object:
Example: Below is an example of a shallow copy.
let employee = {
eid: "E102",
ename: "Jack",
eaddress: "New York",
salary: 50000
};
console.log("Employee=> ", employee);
// Shallow copy
let newEmployee = { ...employee };
console.log("New Employee=> ", newEmployee);
console.log("---------After modification----------");
newEmployee.ename = "Beck";
console.log("Employee=> ", employee);
console.log("New Employee=> ", newEmployee);
- The object contains only primitive values (such as strings and numbers).
- When a shallow copy is created using the spread operator ({ ...employee }), primitive values are copied by value, not by reference.
- As a result, modifying newEmployee.ename does not affect employee.ename.
- Shallow copy problems arise only when objects contain nested reference types like objects or arrays.
- In those cases, both the original and copied objects share the same memory reference, so changes in one affect the other.
Note: Since this object contains only primitive values, modifying the shallow copy does not affect the original object. Shallow copy issues occur only when the object contains nested objects or arrays.
Deep Copy
A deep copy, on the other hand, creates a completely independent copy of the object, including all nested objects or arrays. This ensures that changes made to one object do not affect the other. Each object is stored in a separate memory location, making them entirely independent.
Creating a Deep Copy
Now to create a deep copy of an object in JavaScript we use JSON.parse() and JSON.stringify() methods. Let us take an example to understand it better.
Example: Below is the example of deep copy.
let employee = {
eid: "E102",
ename: "Jack",
eaddress: "New York",
salary: 50000
}
console.log("=========Deep Copy========");
let newEmployee = JSON.parse(JSON.stringify(employee));
console.log("Employee=> ", employee);
console.log("New Employee=> ", newEmployee);
console.log("---------After modification---------");
newEmployee.ename = "Beck";
newEmployee.salary = 70000;
console.log("Employee=> ", employee);
console.log("New Employee=> ", newEmployee);
- A new object is created using JSON.stringify() and JSON.parse() methods in JavaScript.
- JSON.stringify() converts a JavaScript object into a JSON string.
- JSON.parse() converts the JSON string back into a new JavaScript object.
- This approach is useful for small objects with serializable data only.
- It can cause data loss when used on large or complex objects.
- Functions, methods, undefined, and symbols are not serializable and are removed.
- For deep cloning complex objects, libraries like Lodash (_.cloneDeep) are a better option as they handle methods and nested structures safely.
Limitations of JSON.parse() and JSON.stringify()
While the JSON approach is simple, it has its limitations:
- Non-Serializable Properties: Functions, undefined, and certain other non-serializable values are lost when using JSON.stringify().
- Circular References: Objects with circular references will cause JSON.stringify() to throw an error.
- Date Objects: Dates are converted to strings during the process, losing their original type.
Lodash To Deep Copy
Lodash is a JavaScript library that provides multiple utility functions and one of the most commonly used functions of the Lodash library is the cloneDeep() method. This method helps in the deep cloning of an object and also clones the non-serializable properties which were a limitation in the JSON.stringify() approach.
const lodash = require('lodash');
let employee = {
eid: "E102",
ename: "Jack",
eaddress: "New York",
salary: 50000,
details: function () {
return "Employee Name: "
+ this.ename + "-->Salary: "
+ this.salary;
}
}
let deepCopy = lodash.cloneDeep(employee);
console.log("Original Employee Object");
console.log(employee);
console.log("Deep Copied Employee Object");
console.log(deepCopy);
deepCopy.eid = "E103";
deepCopy.ename = "Beck";
deepCopy.details = function () {
return "Employee ID: " + this.eid
+ "-->Salary: " + this.salary;
}
console.log("----------After Modification----------");
console.log("Original Employee Object");
console.log(employee);
console.log("Deep Copied Employee Object");
console.log(deepCopy);
console.log(employee.details());
console.log(deepCopy.details());
Output:

Explanation: Both objects have different properties after the modification. Also, the methods of each object are differently defined and produce different outputs.
const Denque = require("denque");
// Create a queue
const queue = new Denque();
// Enqueue
queue.push("g");
queue.push("f");
queue.push("g");
console.log("Initial queue:", queue.toArray());
// Dequeue
console.log("Dequeued:", queue.shift());
console.log("Queue after dequeue:", queue.toArray());