I Am
Volodymyr Hudyma
<FrontEndDeveloper />
You Are Here: Home/How To Clone An Object In JavaScript?

How To Clone An Object In JavaScript?

May 25, 2020

Table Of Contents

    Due to the fact that objects are reference values in JavaScript, copying them is not as easy as just assigning to another variable.

    There are a lot of different ways to copy an object.

    Choosing the right method depends on what would you like to achieve.

    Before we start with listing the most popular methods and providing use cases for each and every one of them, let's quickly remind ourselves what is shallow and deep copy and the differences between them.

    Shallow Copy

    Shallow copy is a bit-wise copy of an object. A new object is created that has an exact copy of the values in the original object. If any of the fields of the object are references to other objects, just the reference addresses are copied i.e., only the memory address is copied.

    Consider the following example:

    const user = {
      name: "John",
      surname: "Doe",
      other: {
        age: 18,
      },
    };
    
    const newUser = {
      ...user,
    };
    
    newUser.other.age = 22;
    
    // Prints {name: "John", surname: "Doe", age: 22}
    console.log(user);
    
    // Prints {name: "John", surname: "Doe", age: 22}
    console.log(newUser);

    Property otherreferences to an object which contains age.

    When doing a shallow copy, just the reference address of otheris copied, not the value itself.

    That's why when we modify other.ageit gets updated in both userand newUser.

    Deep Copy

    Making a deep copy of an object means copying everything, the newly copied object is completely independent of the original one:

    import cloneDeep from "lodash/cloneDeep";
    
    const user = {
      name: "John",
      surname: "Doe",
      other: {
        age: 18,
      },
    };
    
    const newUser = cloneDeep(user);
    
    newUser.other.age = 22;
    
    // Prints {name: "John", surname: "Doe", age: 18}
    console.log(user);
    
    // Prints {name: "John", surname: "Doe", age: 22}
    console.log(newUser);

    Having in mind the differences between shallow and deep copy, let's start with listing the most popular ways of copying the object:

    Spread Operator

    does a shallow copy

    const user = {
      name: "John",
      surname: "Doe",
      age: 18,
    };
    
    // newUser is a shallow copy of user
    const newUser = {
      ...user,
    };

    Object.assign

    does a shallow copy

    Object.assign(target, ...sources) accepts 2 parameters:

    • target - a target object, where to copy
    • sources - source objects, what to copy

    Copy one source object into an empty target:

    const user = {
      name: "John",
      surname: "Doe",
      age: 18,
    };
    
    // newUser is a shallow copy of user
    const newUser = Object.assign({}, user);

    Copy multiple source objects into an empty target:

    const user = {
      name: "John",
      surname: "Doe",
      age: 18,
    };
    
    const address = {
      street: "Street",
      house: 4,
      flat: 1,
    };
    
    // newUser is a shallow copy of user
    const newUser = Object.assign({}, user, address);

    Copy one source object to an existing target:

    const target = {
      name: "John",
      surname: "Doe",
      age: 18,
    };
    
    const address = {
      street: "Street",
      house: 4,
      flat: 1,
    };
    
    // newUser is a shallow copy of user
    const newUser = Object.assign(target, address);

    Important note: make sure to remember that target object is always mutated.

    JSON Object

    does a deep copy

    Note, that this is not the optimal way of cloning an object, consider using cloneDeep from lodash:

    const user = {
      name: "John",
      surname: "Doe",
      age: 18,
    };
    
    // newUser is a deep copy of user
    const newUser = JSON.parse(JSON.stringify(user));

    You can ask, why is it bad practice? Let me try to explain it to you.

    JSON.stringify converts value to JSON string.

    While it works good with primitives, it has some troubles with:

    • undefined values:
    const obj = {
      key: undefined,
    };
    
    console.log(JSON.stringify(obj)); // Prints "{}"
    • symbols:
    const obj = {
      key: Symbol(),
    };
    
    console.log(JSON.stringify(obj)); // Prints "{}"
    • Date (dates are parsed as strings, which means that you will lose original Date object):
    const obj = {
      key: new Date(),
    };
    
    // Prints Date object: { key: 2020-05-25T14:28:42.155Z }
    console.log(obj); 
    
    // Prints string: {"key":"2020-05-25T14:27:27.413Z"}
    console.log(JSON.parse(JSON.stringify(obj)));
    • circular dependencies:
    const user = {
      name: "John",
      surname: "Doe",
      age: 18,
    };
    
    user.brother = user;
    
    // TypeError: Converting circular structure to JSON
    console.log(JSON.parse(JSON.stringify(user)));
    • and, most importantly, with functions:
    const obj = {
      key: () => {},
    };
    
    console.log(JSON.stringify(obj)); // Prints "{}"

    You can potentially lose some data without even knowing that, as you wouldn't even be warned by the JavaScript.

    Calling JSON.stringify with such data types doesn't throw any errors.

    To sum it up, try to avoid this way of cloning an object.

    Using An External Library

    The best way to create a deep copy of an object - is to use a popular, well tested external library, like lodash.

    lodash

    Lodash provides us with cloneDeep method:

    import cloneDeep from "lodash/cloneDeep";
    
    const user = {
      name: "John",
      surname: "Doe",
      age: 18,
    };
    
    // newUser is a deep copy of user
    const newUser = cloneDeep(user);

    Lodash also implements clone method, which does a shallow copy of an object:

    import clone from "lodash/clone";
    
    const user = {
      name: "John",
      surname: "Doe",
      age: 18,
    };
    
    // newUser is a shallow copy of user
    const newUser = clone(user);

    Custom Method

    There's always a possibility to create your own custom method that would clone an object, but that's like reinventing the wheel.

    You will spend a lot of time writing your own implementation, fixing bugs, and covering the code with unit tests so there's no need to do that.

    Always remember that if you encounter any kind of problem in programming, you are for sure not the first person to face that, so give yourself a try to search for a ready-to-use solution on the internet.

    Summary

    To create a shallow copy of an object use:

    • Spread operator
    • Object.assign method

    To create a deep clone on an object use:

    • JSON object (make sure to understand all pros and cons of this method)
    • External library, like https://lodash.com/docs

    Important note: Never use the assignment operator = for cloning objects.

    Newsletter
    Receive all new posts directly to your e-mail
    No spam, only quality content twice a week
    Let me know what you think about this article
    Click here to write response...