Cloning an array of objects in JavaScript

June 18th 2021 JavaScript TypeScript

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.

Get notified when a new blog post is published (usually every Friday):

If you're looking for online one-on-one mentorship on a related topic, you can find me on Codementor.
If you need a team of experienced software engineers to help you with a project, contact us at Razum.
Copyright
Creative Commons License