Shallow copy

Create a new object that accepts the value of the object you want to copy or reference again. If the object property is of a basic data type, the value of the basic type is copied to the new object. But if the property is a reference data type, then the address in memory is copied, and if one of the objects changes the address in memory, the other object is affected.

Implementation method

Method 1: object.assign

An es6 method used to merge JS objects, etc., and return the target object. It does not copy the inherited and non-enumerable properties of the object

let target = {};
let source = {a: {b:1}};
Object.assign(target,source)
console.log(taget) // {a:{b:1}}
target.a.b = 2;
console.log(taget) // {a:{b:2}}
console.log(source) // {a:{b:2}}
Copy the code

Method two: the extended operator method

/* Copy of the object */
let obj = {a:1.b: {c:1}}
letobj2 = {... obj} obj.a =2
console.log(obj)  //{a:2,b:{c:1}}
console.log(obj2); //{a:1,b:{c:1}}
obj.b.c = 2
console.log(obj)  //{a:2,b:{c:2}} 
console.log(obj2); //{a:1,b:{c:2}}
/* Copy of the array */
let arr = [1.2.3];
let newArr = [...arr]; 
Copy the code

Method 3: Concat and Slice shallow copy arrays

Just for the array type, a new array object is returned.

Concat Shallow copy arraylet arr = [1.2.3];
let newArr = arr.concat();
newArr[1] = 100;
console.log(arr);  // [1, 2, 3]
console.log(newArr); // [1, 100, 3]Slice a shallow copy of an arraylet arr = [1.2, {val: 4}];
let newArr = arr.slice();
newArr[2].val = 1000;
console.log(arr);  //[ 1, 2, { val: 1000 } ]
Copy the code

Deep copy

A complete copy of an object from memory to the target object, and from the heap memory open up a new space to store the new object, and the new object changes will not change the original object, the two to achieve real separation.

Implementation method

Method 1: Beggar version (json.stringify and json.parse)

let obj1 = { a:1.b: [1.2.3]}let str = JSONStringify (obj1);let obj2 = JSONThe parse (STR);console.log(obj2);   / / {a: 1, b: [1, 2, 3]}
obj1.a = 2; obj1.b.push(4);
console.log(obj1);   / / {2, a: b: [1, 2, 3, 4]}
console.log(obj2);   / / {a: 1, b: [1, 2, 3]}
Copy the code

Defect:

  1. If the value of the copied object contains functions, undefined, and symbol, the key-value pair will disappear after the string is serialized through json. stringify
  2. Copying the Date reference type becomes a string
  3. Unable to copy non-enumerable properties
  4. Unable to copy the object’s prototype chain
  5. Copying the RegExp reference type becomes an empty object
  6. An object containing NaN, Infinity, and -infinity will result in null

Hand-written recursive implementation

Basic version

 let obj = {a: {b:1}};
 function deepClone(obj){
  let cloneObj = Object.prototype.toString.call(obj) === "[object Array]" ? [] : {};
   for(let key in obj){
     if(typeof obj[key]=== "object"&& obj ! = =null){
       cloneObj[key] = deepClone(obj[key])
     }else{
       cloneObj[key] = obj[key]
     }
   }
   return cloneObj;
 }
 let obj2 = deepClone(obj);
 obj2.a.b = 33
 console.log("obj",obj) // {a:{b:1}}
 console.log("obj2",obj2) // {a:{b:33}}
Copy the code

Defect:

  1. Cannot copy non-enumerable properties and Symbol types
  2. This method only recursively copies values for normal reference types, and does not copy correctly for Array, Date, RegExp, Error, Function and other reference types
  3. The properties of the object are looped, i.e. circular references are not resolved

Improved version

const isComplexDataType = obj= > (typeof obj === 'object' || typeof obj === 'function') && (obj ! = =null)
const deepClone = function (obj, hash = new WeakMap(a)) {
  if (obj.constructor === Date) 
  return new Date(obj)       // The date object returns a new date object
  if (obj.constructor === RegExp)
  return new RegExp(obj)     // The regular object directly returns a new regular object
  // If circular reference is used, weakMap is used to solve the problem
  if (hash.has(obj)) return hash.get(obj)
  let allDesc = Object.getOwnPropertyDescriptors(obj)
  // Iterate over the properties of all the keys passed in
  let cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc)
  // Inherit the prototype chain
  hash.set(obj, cloneObj)
  for (let key of Reflect.ownKeys(obj)) { 
    cloneObj[key] = (isComplexDataType(obj[key]) && typeofobj[key] ! = ='function')? deepClone(obj[key], hash) : obj[key] }return cloneObj
}
Copy the code

Handwritten deep copy reference: juejin.cn/post/689663… Juejin. Cn/post / 684490…

Other implementation methods

Lodash library _.clonedeep method, jquery.extend () method

FAQ: The difference between assignment and shallow copy

Note: The premises are for reference types

The assignment

When we assign an object to a new variable, we assign that object’s address on the stack, not the data in the heap. In other words, the two objects point to the same storage space. No matter which object changes, it is the contents of the changed storage space. Therefore, the two objects are linked.

let a = {name:'jimmy'.b: {age:12}}
let b = a;
b.name = 'chimmy';
b.b.age = 21;
console.log(a) // {name:'chimmy',b:{age:21}}
console.log(b) // {name:'chimmy',b:{age:21}}
Copy the code

Shallow copy

When memory is created again in the heap, the basic data types of objects before and after the copy do not affect each other, but the reference types of objects before and after the copy do not affect each other because they share the same memory.

let a = {name:'jimmy'.b: {age:12}}
letb = {... a}; b.name ='chimmy';
b.b.age = 21;
console.log(a) // {name:'jimmy',b:{age:21}}
console.log(b) // {name:'chimmy',b:{age:21}}
Copy the code

Deep copy

A complete copy of an object from memory to the target object, and from the heap memory open up a new space to store the new object, and the new object changes will not change the original object, the two to achieve real separation.

let a = {name:'jimmy'.b: {age:12}}
letb = {... a}; b.name ='chimmy';
b.b.age = 21;
console.log(a) // {name:'jimmy',b:{age:12}}
console.log(b) // {name:'chimmy',b:{age:21}}
Copy the code