In project development, we often encounter the need to copy an object or array, but cannot change the original object, so we need to use copy, which is divided into deep copy and shallow copy

Shallow copy

Create a new object of your own to accept the object values you want to copy or reference again. If the object property is a primitive data type, the value of the primitive type is copied to the new object. But if the property is a reference data type, the copy is the address in memory, and if one object changes the address in memory, the other object must be affected. There are many shallow copy methods such as object.assign (), extension operator {… Obj}, Array array.from (), etc. I don’t want to list them all. Write a shallow copy by hand

Train of thought

  • Make a basic copy of the base type;
  • Create a new store for reference types and copy a layer of object properties;
    var Obj = { 
            func: function () { alert(1)},obj: {a:1.b: {c:2}},
            arr: [1.2.3].und: undefined.reg: / 123 /,
            date: new Date(0), 
            NaN: NaN.infinity: Infinity.sym: Symbol(1)}const shallowClone = (target) = > {
    if (typeof target === 'object'&& target ! = =null) {
      const cloneTarget = Array.isArray(target) ? [] : {};for (let prop in target) {
        if(target.hasOwnProperty(prop)) { cloneTarget[prop] = target[prop]; }}return cloneTarget;
    } else {
      return target;
    }
  }
  shallowClone(Obj)
Copy the code

The results are as follows

Deep copy

A complete copy of an object from memory to the target object, and a new space in the heap memory to store the new object, and the modification of the new object does not change the original object, the two achieve true separation

Json.stringfy () is the simplest deep-copy method in development so far, but there are some problems with this method copy, as shown in the following code

    var Obj = { 
        func: function () { alert(1)},obj: {a:1},
        arr: [1.2.3].und: undefined.reg: / 123 /,
        date: new Date(0), 
        NaN: NaN.infinity: Infinity.sym: Symbol(1)}Object.defineProperty(Obj,'innumerable', {enumerable:false.value:'innumerable'
  })
  JSON.parse(JSON.stringfy(Obj));
Copy the code

The result is shown below Pay attention to

  • If the value of the copied object is function, undefined, or symbol, the key/value pair will disappear in the string serialized by json. stringify.
  • The prototype chain of the object cannot be copied, the attribute of the object cannot be enumerated, and the circular application of the object, that is, the object is looped (obj[key] = obj);
  • Copying the Date reference type becomes a string;
  • Copying a RegExp reference type becomes an empty object.
  • Object containing NaN, Infinity, and -infinity, the result of JSON serialization is null;

This method does not copy all the attributes of the object, but is sufficient to meet the needs of daily development

Recursive deep copy

    // The object to copy
     var obj = {
      num: 0.str: ' '.boolean: true.unf: undefined.nul: null.obj: { name: 'object'.id: 1.gender: 1  },
      arr: [0.1.2].func: function () { console.log('function')},date: new Date(0),
      reg: new RegExp('/ regular/ig'),Symbol('1')]: 1};Object.defineProperty(obj, 'innumerable', {
      enumerable: false.value: 'Non-enumerable properties'}); obj =Object.create(obj, Object.getOwnPropertyDescriptors(obj))
    obj.loop = obj    // Set loop to a property referenced in a loop
    // Determine the data type
    function ifType(val){
      let type  = typeof val;
      if(type ! = ="object") {
        return type;
      }
      return Object.prototype.toString.call(val).replace(/^\[object (\S+)\]$/.'$1');
    }
    // Copy the code
    const deepClone = function (obj, hash = new WeakMap(a)) {
      if (ifType(obj) === 'Date') 
      return new Date(obj)       // The date object returns a new date object
      if (ifType(obj) === 'RegExp')
      return new RegExp(obj)     The regular object returns a new regular object directly
      // If the loop is referenced, use weakMap
      if (hash.has(obj)) return hash.get(obj)
      let allDesc = Object.getOwnPropertyDescriptors(obj)
      // Walks through the properties of all keys of the passed argument
      let copyObj = Object.create(Object.getPrototypeOf(obj), allDesc)
      // Inherit the prototype chain
      hash.set(obj, copyObj)
      const isType = obj= > (typeof obj === 'object' || typeof obj === 'function') && (obj ! = =null)
      for (let key of Reflect.ownKeys(obj)) { 
        copyObj[key] = (isType(obj[key]) && typeofobj[key] ! = ='function')? deepClone(obj[key], hash) : obj[key] }return copyObj
    }
 / / verification
let copyObj = deepClone(obj)
copyObj.arr.push(4)
console.log('Original object obj', obj)
console.log('Copied object copyeObj', copyObj)
Copy the code

In addition to the above, the _. CloneDeep method provided by the loDash library can also implement deep copy