This is the 12th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

In this series of interviews, you’ll learn how to copy in JavaScript and how to write deep and light copies by hand.

If you feel helpful, please click 👍 to encourage you

What is copy

Copy is actually replication. In many scenarios, we need to copy a copy of data, and then operate the copied data, which may not affect the original data, or may require some linkage with the original data. Therefore, according to the functions of deep copy and shallow copy, the two requirements can be met.

A copy of the value type

There is no such thing as a deep copy of a value type. Because the copied value type does not correlate with the original data, changing the copied value does not change the original data.

  let a = 1
  let b = a
  b = 2
  console.log(a) / / = > 1
  console.log(b) / / = > 2
Copy the code

Shallow copy

When memory is re-created in the heap, the base types before and after the copy do not affect each other, and the reference types before and after the copy still share the same memory, so they affect each other.

Here’s an example:

  // Define a shallow copy function
  function shallowCopy(obj) {
    const cloneObj = {}
    for (let i in obj) {
      if (obj.hasOwnProperty(i)) {
        cloneObj[i] = obj[i]
      }
    }
    return cloneObj
  }

  / / declare the person
  let person = {
    name: "Zhang".hobbies: ["Eat"."Sleep"."Beat the beans."]}// Make a shallow copy of person to get person1
  let person1 = shallowCopy(person)

  // Change the value type
  person1.name = 'bill'

  // Change the reference type
  person1.hobbies[0] = 'beauty'

  console.log(person);
  console.log(person1);
Copy the code

As you can see, when we change the person1 value type attribute name, it doesn’t affect the Person name, but when we change the reference type hobbies, the Person changes with person1, which is a shallow copy.

In addition to the above, shallow copy implementations include object.assign (), the expansion operator… ., array slice () array concat ().

Deep copy

Create a new area of heap memory to store the new object, make a recursive copy of all attributes of the original object, and also create a new area for all attributes of reference type, modify the new object does not affect the original object.

From the shallow copy example above, we can see that the person’s hobbies is a reference type, but each element of the hobbies is a string, that is, a value type, so the hobbies will not affect each other as long as we shallow copy the hobbies again. So we can conclude that if we make a shallow copy of an object recursively, the end result is a deep copy.

Recursive shallow copy

The code is as follows, allowing for special cases.

// Define a deep-copy function
  function deepClone(obj) {
    const cloneObj = new obj.constructor()
    if (obj === null) return obj
    if (obj instanceof Date) return new Date(obj)
    if (obj instanceof RegExp) return new RegExp(obj)
    if (typeofobj ! = ='object') return obj
    for (let i in obj) {
      if (obj.hasOwnProperty(i)) {
        cloneObj[i] = deepClone(obj[i])
      }
    }
    return cloneObj
  }

  / / declare the person
  let person = {
    name: "Zhang".hobbies: ["Eat"."Sleep"."Beat the beans."]}// Make a shallow copy of person to get person1
  let person1 = deepClone(person)

  // Change the value type
  person1.name = 'bill'

  // Change the reference type
  person1.hobbies[0] = 'beauty'

  console.log(person);
  console.log(person1);
Copy the code

The result is as follows, only Li Si likes beautiful women now. That means our deep copy is successful.

JSON.parse(JSON.stringify())

Parse (json.stringify ()) in addition to implementing deep copy recursively in the shallow copy way above, you can use json.parse (json.stringify ()) to achieve the same result.

But this approach has its drawbacks. Let’s take a look

  / / declare the person
  let person = {
    name: "Zhang".hobbies: ["Eat"."Sleep"."Beat the beans."].date: new Date.fuc: () = >{},reg: /w/
  }

  // Make a shallow copy of person to get person1
  const person1 = JSON.parse(JSON.stringify(person));


  // Change the value type
  person1.name = 'bill'

  // Change the reference type
  person1.hobbies[0] = 'beauty'

  console.log(person);
  console.log(person1);
Copy the code

As a result, the date property changes from an object to a string, the FUc property disappears, and the reg property becomes an empty object. So this way is very bad, not careful there will be accidents.

  • undefined, any function andsymbolValue is ignored during serialization;
  • DateDates are treated as strings;
  • NaNInfinityThe value of the format andnullWill be regarded asnull;
  • Other types of objects, includingMap/Set/WeakMap/WeakSet, only enumerable attributes are serialized;
  • Executing this method on objects that contain circular references (objects that refer to each other in an infinite loop) throws an error;

Let’s use the recursive shallow-copy method to see the result, which is exactly the same.