There are two main data types in JavaScript:

  • Basic type Number String NULL Undefined Boolean symbol
  • Reference type Array Object function

Basic type data is stored in stack memory

Reference type data is stored in heap memory, and the variable of a reference data type is a reference to an actual object in heap memory, which is stored on the stack

Shallow copy

Shallow copy refers to the creation of new data that has an exact copy of the original data attribute values

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

That is, shallow copies copy a layer, and deep reference types share memory addresses

Let’s simply implement a shallow copy

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

In JavaScript, shallow copies exist:

  • Object.assign
  • Array.prototype.slice(), Array.prototype.concat()
  • Replication using extended 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);
Copy the code

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"]
Copy the code

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"]
Copy the code

Extended operator

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

Deep copy

Deep copy opens up a new stack. Two object families are identical but correspond to two different addresses. Modifying the properties of one object does not change the properties of the other

Common deep-copy modes are:

  • _.cloneDeep()
  • jQuery.extend()
  • JSON.stringify()
  • Handwriting loop recursion

_.cloneDeep()

const _ = require('lodash');
const obj1 = {
    a: 1.b: { f: { g: 1}},c: [1.2.3]};const obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);// false
Copy the code

jQuery.extend()

const$=require('jquery');
const obj1 = {
    a: 1.b: { f: { g: 1}},c: [1.2.3]};const obj2 = $.extend(true, {}, obj1);
console.log(obj1.b.f === obj2.b.f); // false
Copy the code

JSON.stringify()

const obj2=JSON.parse(JSON.stringify(obj1));
Copy the code

However, this approach has the disadvantage of ignoring 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"}
Copy the code

Cycle recursion

function deepClone(obj, hash = new WeakMap(a)) {
  if (obj === null) return obj; // If it is null or undefined, I will not copy it
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  // May be objects or ordinary values if functions do not need deep copies
  if (typeofobj ! = ="object") return obj;
  // Make a deep copy of an object
  if (hash.get(obj)) return hash.get(obj);
  let cloneObj = new obj.constructor();
  // Find the constructor from the parent class stereotype, which points to the current class itself
  hash.set(obj, cloneObj);
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      // Implement a recursive copycloneObj[key] = deepClone(obj[key], hash); }}return cloneObj;
}
Copy the code

Fourth, the difference between

Here are two images to help you see the difference between a shallow copy and a deep copy

As you can see from the above figure, both shallow and deep copies create a new object, but behave differently when copying object properties

Shallow copy only copies the pointer that the attribute points to an object, but not the object itself. The old and new objects still share the same memory. Modifying object attributes affects 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 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 ] }
Copy the code

But deep copy will create another identical object, the new object and the original object do not share memory, modify the new object will not change to the original object

/ / 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 ] }
Copy the code

summary

If the copy type is reference type:

  • A shallow copy is a copy of a layer. If the property is an object, the shallow copy is a copy. The two objects point to the same address
  • Deep copy is a deep recursive copy. If the property is an object, the deep copy is a new stack, and the two objects point to different addresses

Conclusion:

  • Deep copy recursively copies all values or attributes in the new object, while copy copies only references.
  • In a deep copy, changes in the new object do not affect the original object, while in a shallow copy, changes in the new object are changed in the original object.
  • In the deep copy, the original object does not share the same properties as the new object, while in the shallow copy, they have the same properties.