To understand js deep and shallow replication, we first need to understand the concepts: heap, stack, data type, reference type

Heap and stack characteristics

Pile:

  • Store reference type data
  • Access by reference
  • Storage space is dynamically allocated
  • Unordered storage, which can be obtained directly by reference
  • Large storage space, but relatively low operating efficiency

The stack:

  • Store the underlying data types
  • According to the value of access
  • Fixed storage space
  • The system automatically allocates memory space
  • Small space, high operating efficiency
  • First in, last out, last in, first out

The data type

Basic types of

Basic data types: undefined, Boolean, number, string, null

Basic data types are stored on the stack, directly by value, so they can be accessed directly

The value of a basic datatype is immutable. If you change the value of a basic datatype dynamically, its original value does not change

    var str = "abc";

    console.log(str[1]="f");    // f

    console.log(str);           // abc

Copy the code

As you can see, the original value of STR has not changed. They only return a new string, and the value of the original string does not change. So remember, the values of primitive data types are immutable.

The basic type of comparison is the comparison of values, which are considered equal as long as their values are equal.

It is best to use strict, because == is cast

var a = 1; var b = 1; console.log(a === b); //true


    var a = 1;
    var b = "1"; console.log(a === b); //falseVar a = 1; var b =true; console.log(a == b); //trueType conversion is performedCopy the code

Reference type: object

A reference type (object) is stored in heap memory. The variable is actually a pointer stored in stack memory that points to an address in heap memory. Each space size is different, and specific allocation should be made according to the situation, for example:

var person1 = {name:'jozo'};
var person2 = {name:'xiaom'};
var person3 = {name:'xiaoq'};

Copy the code

Reference type equivalents can be changed for example:

Var a = [1, 2, 3]; a[1] = 5; console.log(a[1]); / / 5Copy the code

A comparison of reference types is a comparison of references, so every time we operate on a reference type in JS, we operate on the reference of its object (the pointer stored in the stack memory), so we compare two reference types to see whether their reference refers to the same object

Var a = [1, 2, 3]; Var b = [1, 2, 3]; console.log(a === b); //false

Copy the code

Although variable A and variable B both represent an array of 1, 2, and 3, their locations in memory are different, that is to say, variable A and variable B do not point to the same object or the same heap memory space. So they’re not equal.

Value and address transmission

Now that we know the difference between primitive data types and reference types, we should be able to understand the difference between value and address. When we do the assignment, the assignment (=) of the base data type is to create a new stack in memory and then assign the value to the new stack. Such as:

var a = 10; var b = a; a ++ ; console.log(a); // 11 console.log(b); / / 10Copy the code

Therefore, the two variables assigned by a primitive type are independent variables that do not affect each other

But assignment of a reference type is an address. Just changing the pointer, for example, means that an assignment of a reference type is an assignment of the address of the object stored on the stack, so that both variables refer to the same object, so that operations on both variables affect each other. For example,

var a = {}; Var a = a; var b = a; // both a and b refer to the empty object a.name ='jozo';
console.log(a.name); // 'jozo'
console.log(b.name); // 'jozo'b.age = 22; console.log(b.age); // 22 console.log(a.age); // 22 console.log(a == b); //true

Copy the code

Shallow copy

With the above knowledge base, it’s easy to understand shallow copies. Look at the following example to see the difference between shallow copy and direct assignment:

var obj1 = {
        'name' : 'zhangsan'.'age' :  '18'.'language': [1, 2, 3], [4, 5]],}; var obj2 = obj1; var obj3 = shallowCopy(obj1);function shallowCopy(src) {
        var dst = {};
        for (var prop in src) {
            if(src.hasOwnProperty(prop)) { dst[prop] = src[prop]; }}return dst;
    }

    obj2.name = "lisi";
    obj3.age = "20";

    obj2.language[1] = ["二"."Three"];
    obj3.language[2] = ["Four"."Five"];

    console.log(obj1);
    //obj1 = {
    //    'name' : 'lisi', / /'age' :  '18', / /'language': 1, [["二"."Three"], ["Four"."Five"]], / /}; console.log(obj2); //obj2 = { //'name' : 'lisi', / /'age' :  '18', / /'language': 1, [["二"."Three"], ["Four"."Five"]], / /}; console.log(obj3); //obj3 = { //'name' : 'zhangsan', / /'age' :  '20', / /'language': 1, [["二"."Three"], ["Four"."Five"]], / /};Copy the code

From the print above, we can see that changing the assigned object obj2 also changes the original object obj1, while changing the shallow copy of obj3 does not change the original object obj1. This shows that the assigned object obj2 only changes the pointer to the same object, while the shallow copy of obj3 recreates the new object.

However, let’s see what happens when we change the reference type. I also change the second and third values of the language property in obj2, the assigned object, and in obj3, the shallow copy (language is an array, that is, the reference type). As you can see from the output, both the assignment object obj2 and the shallow copy object obj3 change the original data.

From this code we can know:

    function shallowCopy(src) {
        var dst = {};
        for (var prop in src) {
            if(src.hasOwnProperty(prop)) { dst[prop] = src[prop]; }}return dst;
    }
Copy the code

Shallow copy copies only one layer of the object’s properties, not the reference type of the object’s data. So changing the reference type in obj3 from a shallow copy changes the original data.

We can use a diagram to show the difference between deep copy, shallow copy, and assignment:

Deep copy

Deep copy is a copy of an object and all its children. We simply iterate over all the property types belonging to an object and assign them to another object. Look at the following code:

   functionDeepClone (obj) {// Return the same object if it is not a complex data typeif(typeof obj ! ="object") {returnVar newObj = {};for (var key in obj) {
          newObj[key] = deepClone(obj[key])
        }
        return newObj;
    }
Copy the code

The main recursion is to continue shallow copying if the child element is of object type.

Deep Copy Optimized edition:

Weakmap const deepClone = (value,hash = new WeakMap) => {
  if(value == null) return value;
  if(value instanceof RegExp) return new RegExp(value);
  if(value instanceof Date) return new Date(value);
  if(typeof value ! ='object') return value;
  let obj = new value.constructor();
  console.log('hash value:.hash, value, obj)

  if(hash.get(value)){
    return hash.get(value);
  }
  hash.set(value, obj);
  for(var k in value) {
    if(value.hasOwnProperty(k)){
      console.log('base slot', k, value[k])
      obj[k] = deepClone(value[k], hash); }}return obj;
}

let a = {
  m: 1,
  n:{
    x:12,
    y:13
  }
}
a.self = a;
letb = deepClone(a); b.n = 100; console.log(b); // {m: 1, n: 100} console.log(a); // {m: 1, n: {x: 12, y:13}} Scheme 2: recursive + array deduplicationfunction find(arr,item){
  for(var i=0; i<arr.length; i++){
    if(arr[i].source === item){
      return arr[i]
    }
  }
  return null;
}

function isObject(obj) {
  return typeof obj === 'object'&& obj ! = null; }function deepClone(source,uniqueList){
  if(! isObject(source)) return source; // Whether it is an objectif(! uniqueList) uniqueList = []; Var target = array.isarray (source)? [] : {}; Var uniqueData = find(uniqueList,source);
  if(uniqueData) return uniqueData.target;
  uniqueList.push({
    source:source,
    target:target
  });

  for(var key in source) {if(Object.prototype.hasOwnProperty.call(source,key)){
       target[key] = deepClone(source[key], uniqueList) // pass array}}return target;
}

const a = {
  name:"key1",
  eat:[The word "apple"."Banana"]
}

a.d = a;
b = deepClone(a);
a.eat[2] = "Peach";
console.log('Data source', a);
console.log(b)

Copy the code

So far is not the shallow copy, deep copy has a clear understanding.