This is the 9th day of my participation in the August More Text Challenge

When coding in JavaScript, we often encounter situations where we need to copy objects or arrays, but sometimes it doesn’t work as expected. Let’s take a look!

Various types of data copying

Let’s start with an example

Copy number

You can see that all the results are normal

Copy string

You can see that the results are all normal

Copying arrays (wrong version)

We can see the following example

Expectations are

  • Make a copy of the list to Box
  • [1,2,3,’a’]
  • [1,2,3,4,’b’]

The actual effect is

  • When you change the list, the box is also changed
  • When you change box, you change list

Copy object (wrong version)

We can see from the following example

  • Object A only changed the blog, should get

     {
       blog:'0',
       author:'Axjy'
    }
    Copy the code
  • Object B only changes author, should get

 {
   blog:'jueJin',
   author:'1'
}
Copy the code

But you can see the end result, it’s all changed

 {
   blog:'0',
   author:'1'
}
Copy the code

We can see that both array copy and object copy are different from what we expected, and the interaction between original data and new data is mutual. From this we can introduce the concept of shallow copy.

Shallow copy

Shallow copy is a bit-by-bit copy of an object. Creates a new object with an exact copy of the value in the original object. If any field of an object is a reference to another object, only the reference address is copied, that is, the memory address is copied. By default, reference types (object) are shallow copies.

The result of the copy is that both objects point to the same address, so if you change the properties of one object, the properties of the other object also change.

Deep copy

The deep copy copies all fields and dynamically allocated memory to which the fields point. Deep copy occurs when an object and the object it references are copied. Basic data types (number, String, NULL, undefined, Boolean) are deep-copied by default.

Deep copy creates A new stack, two objects correspond to two different addresses, and changing the properties of object A does not affect object B

Array deep copy scheme

Array deep copy can be implemented using the following methods

  • useslice()
  • useconcat()
  • ES6 extension operator
  • Array.form()
let box = list.slice(); // let box = []. Concat (list); // let box = [...list]; // let box = array. from(list); / / fourCopy the code

Object. Assign problem for deep copy objects

Before we talk about deep copy, let’s look at object.assign ().

Looking at the following example, the results alone seem good

let B = Object.assign({},A);
Copy the code

But what if we make some changes?

Such as the following example

  • Inside object A is nested A layer of object C,
  • 【 modify 】A, b, C,
  • 【 Result 】 At the same time that C in A is changed, B is also changed.

Object.assign() is a deep copy or a shallow copy?

define

The object.assign () method is used to assign the values of all enumerable properties from one or more source objects to target objects. It will return the target object. MDN document

For deep copy

Object.assign() copies (enumerable) property values. If the source value is a reference to an object, it simply copies its reference value.

Assign ({},Obj); if the Object attribute value is a simple type (such as Number, String), the new Object obtained by object.assign ({},Obj) is a deep copy. If the attribute value is an object or some other reference type, it is actually shallow-copied for that object.

Using destruct assignment and extension operators (…) You will find the same situation as above.

Object deep copy scheme

Using JSON. Stringify

Json.stringify converts the object to a string, json.parse converts the string to a new object,

Note: This method can only be used for objects that can be converted to JSON, not if the object contains function or RegExp.

let B = JSON.parse(JSON.stringify(A))
Copy the code

Using a recursive

Here are three things to note:

Use the new obj.constructor () function to create an empty object instead of {} or [], which preserves inheritance from the original chain.

2, use obj. HasOwnProperty (key) to check whether the property is from the prototype chain, because for.. in.. It also iterates through enumerable properties on its prototype chain.

3. The above function uses a recursive algorithm, which is fine if the function has a name and the name will never change. But the problem is that the execution of this function is tightly coupled with the name factorial. To eliminate this tight coupling, you need to use arguments.callee.

var clone = function (obj) { 
    if(obj === null) return null 
    if(typeof obj !== 'object') return obj;
    if(obj.constructor===Date) return new Date(obj); 
    if(obj.constructor === RegExp) return new RegExp(obj);
    var newObj = new obj.constructor ();  //保持继承链
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {   //不遍历其原型链上的属性
            var val = obj[key];
            newObj[key] = typeof val === 'object' ? arguments.callee(val) : val; // 使用arguments.callee解除与函数名的耦合
        }
    }  
    return newObj;  
}; 
Copy the code

This method comes from: how to make a deep copy of objects in JS; To explore more deep-copy objects, take a look at this deep JS deep-copy object

Reference:

object.assign()-MDN

Shallow Vs Deep Copy In Javascript

Understanding Deep and Shallow Copy in Javascript


Leave a like if you get something! 😘