How to understand shallow copy and deep copy

1, Data type storage

There are two data types in JavaScript:

  • Basic type

  • reference type

The basic type data is saved in stack memory

Reference type data is stored in heap memory. The variable of reference data type is a reference to the actual object in heap memory and exists in the stack

2, Shallow copy

Shallow copy refers to the creation of new data, which has an accurate copy of the attribute value of the original data

If the attribute is a base type, the value of the base type is copied. If the attribute is a reference type, the memory address is copied

That is, a shallow copy is a copy layer, and a deep reference type is a shared memory address

Here's a simple implementation of a shallow copy

function shallowClone(obj) {
    const newObj = {};
    for(let prop in obj) {
        if(obj.hasOwnProperty(prop)){
            newObj[prop] = obj[prop];
        }
    }
    return newObj;
}

In JavaScript, there are shallow copies:

  • Object.assign

  • Array.prototype.slice(), Array.prototype.concat()

  • Replication using extension operators

Object.assign

var obj = {
    age: 18,
    nature: ['smart', 'good'],
    names: {
        name1: 'fx',
        name2: 'xka'
    },
    love: function () {
        console.log('fx is a great girl')
    }
}
var newObj = Object.assign({}, fxObj);

slice()

const fxArr = ["One", "Two", "Three"]
const fxArrs = fxArr.slice(0)
fxArrs[1] = "love";
console.log(fxArr) // ["One", "Two", "Three"]
console.log(fxArrs) // ["One", "love", "Three"]

concat()

const fxArr = ["One", "Two", "Three"]
const fxArrs = fxArr.concat()
fxArrs[1] = "love";
console.log(fxArr) // ["One", "Two", "Three"]
console.log(fxArrs) // ["One", "love", "Three"]

Extension operator

const fxArr = ["One", "Two", "Three"]
const fxArrs = [...fxArr]
fxArrs[1] = "love";
console.log(fxArr) // ["One", "Two", "Three"]
console.log(fxArrs) // ["One", "love", "Three"]

3, Deep copy

Deep copy opens up a new stack. The properties of two objects are the same, but corresponding to two different addresses. Modifying the properties of one object will not change the properties of the other object

Common deep copy methods include:

  • _.cloneDeep()

  • Handwriting loop recursion

JSON.stringify()

const obj2=JSON.parse(JSON.stringify(obj1));

However, there are disadvantages in this method, which ignores undefined, symbol and functions

const obj = {
    name: 'A',
    name1: undefined,
    name3: function() {},
    name4:  Symbol('A')
}
const obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj2); // {name: "A"}

Circular recursion

function deepClone(obj, hash = new WeakMap()) {
  if (obj === null) return obj; //  If it is null or undefined, I will not copy
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  //  It could be an object or a normal value    If it's a function, you don't need a deep copy
  if (typeof obj !== "object") return obj;
  //  If it is an object, you need to make a deep copy
  if (hash.get(obj)) return hash.get(obj);
  let cloneObj = new obj.constructor();
  //  The constructor on the prototype of the class is found, and the constructor on the prototype is not found   The constructor points to the current class itself
  hash.set(obj, cloneObj);
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      //  Implement a recursive copy
      cloneObj[key] = deepClone(obj[key], hash);
    }
  }
  return cloneObj;
}

4, Distinction

First of all, with the help of two figures, you can see the difference between shallow copy and deep copy more clearly

It is found from the above figure that both shallow copy and deep copy create a new object, but the behavior is different when copying object attributes

Shallow copy only copies the pointer of the attribute to an object, not the object itself. The old and new objects still share the same block of memory. Modifying the object attribute will affect the original object

//  Shallow copy
const obj1 = {
    name : 'init',
    arr : [1,[2,3],4],
};
const obj3=shallowClone(obj1) //  A shallow copy method
obj3.name = "update";
obj3.arr[1] = [5,6,7] ; //  Old and new objects still share the same block of memory

console.log('obj1',obj1) // obj1 { name: 'init',  arr: [ 1, [ 5, 6, 7 ], 4 ] }
console.log('obj3',obj3) // obj3 { name: 'update', arr: [ 1, [ 5, 6, 7 ], 4 ] }

But deep copy as like as two peas will create another object that is exactly the same. New objects do not share memory with original objects.

//  Deep copy
const obj1 = {
    name : 'init',
    arr : [1,[2,3],4],
};
const obj4=deepClone(obj1) //  A deep copy method
obj4.name = "update";
obj4.arr[1] = [5,6,7] ; //  The new object does not share memory with the original object

console.log('obj1',obj1) // obj1 { name: 'init', arr: [ 1, [ 2, 3 ], 4 ] }
console.log('obj4',obj4) // obj4 { name: 'update', arr: [ 1, [ 5, 6, 7 ], 4 ] }

Summary

If the copy type is reference type:

  • Shallow copy is a copy layer. When the attribute is an object, shallow copy is a copy, and the two objects point to the same address

  • Deep copy is a recursive deep copy. When the attribute is an object, deep copy is a new stack, and the two objects point to different addresses

Tags: Javascript Vue.js

Posted on Tue, 07 Sep 2021 16:44:06 -0400 by melkara