Cloning an array of objects in JavaScript
Cloning arrays in JavaScript is a topic I get asked about regularly by other team members. This post is intended as a reference that I can refer to on similar occasions in the future.
Depending on the requirements, two different approaches can be taken. I will use an array of people to demonstrate the differences in behavior between the two:
beforeEach(() => {
people = [
{ name: "John", surname: "Doe" },
{ name: "Jane", surname: "Doe" },
];
});
Shallow copy
Shallow copy involves creating a separate array that references the same objects. The easiest way to accomplish this is to use spread syntax:
export function shallowClone<T>(array: T[]): T[] {
return [...array];
}
Adding objects to the new array or removing objects from it does not affect the original array:
it("creates a separate array", () => {
const clone = shallowClone(people);
clone.push({ name: "Jack", surname: "Smith" });
expect(clone).toHaveLength(3);
expect(people).toHaveLength(2);
});
Changing an object in the new array also affects the object in the original array:
it("shares objects in array", () => {
const clone = shallowClone(people);
clone[0].name = "Jack";
expect(clone[0].name).toBe("Jack");
expect(people[0].name).toBe("Jack");
});
Deep copy
Deep copying creates an array that also contains complete copies of the objects. The most reliable way to do this is to serialize the array and deserialize it again (this only works for object graphs that are trees, i.e. do not contain loops or cross-references):
export function deepClone<T>(array: T[]): T[] {
return JSON.parse(JSON.stringify(array));
}
Adding objects to the new array or removing objects from it still has no effect on the original array:
it("creates a separate array", () => {
const clone = deepClone(people);
clone.push({ name: "Jack", surname: "Smith" });
expect(clone).toHaveLength(3);
expect(people).toHaveLength(2);
});
However, changing an object in the new array has no effect on the object in the original array:
it("creates separate objects in array", () => {
const clone = deepClone(people);
clone[0].name = "Jack";
expect(clone[0].name).toBe("Jack");
expect(people[0].name).toBe("John");
});
You can download the full code from my GitHub repository and run the tests yourself.
Creating a shallow or deep clone of an array in JavaScript requires only one line of code. Just be sure you know what you need before you decide which approach to use.