Coding With Fun
Home Docker Django Node.js Articles FAQ

Perfect for deep and shallow copies of JavaScript


Jun 01, 2021 Article blog


Table of contents


preface

"Copy" has always been a hot topic for interviews. S eemingly simple, but it is difficult to live a lot of interviewers, the answer sloppy, ambiguous. Take the time to analyze and summarize the "copy" and let the puzzle disappear completely.

body

From a story, yesterday because the hospital can not open medicine, I took medicine to take the community pharmacy to buy medicine, after entering the door I asked the boss whether there is this medicine, the boss turned into a small room to take a box of medicine, it is true, the name of the medicine and milligram touch the same, but the appearance of the box and manufacturers are not the same, I asked the boss: "These two drugs are a medicine, the box is not the same ah, the ingredients of the drug is the same?" " The boss said of course, this is the same as you go to buy pork, the same as pig meat, but you go to this supermarket and go to other supermarkets to buy the same place." Finally, I didn't buy the medicine for safety reasons.

Copy is divided into shallow and deep copies. I t is for 对象 if not objects. T he object here can be understood as the box of medicine I took, 浅拷贝 can be understood as the box taken by the boss, although the name of the medicine is the same as milligrams, and then inside we do not know whether it is really the same, may be the same may not be the same. 深拷贝 can be understood for me to buy a touch of the same medicine, layer by layer of drug name, milligrams, manufacturers, ingredients are the same.

summary:

  • Shallow copies are copied in turn for the properties of an object, copying only one layer, not recursively to a property copy, resulting in a 引用 problem that is, the memory address refers to the same address. Simply put, after copying, it's 有关 the original object.
  • A deep copy is a recursive copy to a new object for each property of an object, and the memory address does not point to the same address. Simply put, copying is 无关

Here's an example of a shallow copy:

let school={'name':"W3Cschool"};
let my = {age:{count:18},name:"W3Cschool编程狮"};
let all = {...school,...my};
my.age.count=100;
console.log(all);
console.log(my);

outcome:

{ age: { count: 100 }, name: 'W3Cschool编程狮' }
{ age: { count: 100 }, name: 'W3Cschool编程狮' }

The conclusion is that the properties on the object after the shallow copy is modified will modify the properties on the original object at the same time.

Here's another example of a deep copy:

const _ = require("loadsh")
let my = {age:{count:18},name:"W3Cschool编程狮"};
let all = _.cloneDeep(my);
all.age.count =100;
console.log(my);
console.log(all);

outcome:

{ age: { count: 18 }, name: 'W3Cschool编程狮' }
{ age: { count: 100 }, name: 'W3Cschool编程狮' }

The conclusion is that the properties on the object after the deep copy is modified do not modify the properties on the original object at the same time.

The method of copying

1. Array methods: slice and concat

  • slice

let arr = [1,2,3,4];
let arr2 = arr.slice(0)
arr2[2]=5;


console.log(arr);  //[ 1, 2, 3, 4 ]
console.log(arr2); //[ 1, 2, 5, 4 ]

When the array is not an object, it is a deep copy from the result, in the following example

let arr = [{1:1,2:2}];
let arr2 = arr.slice(0)
arr2[2]=5;


console.log(arr);  //[ { '1': 1 }, { '2': 5 } ]
console.log(arr2); //[ { '1': 1 }, { '2': 5 } ]

When an object is in an array, it becomes a shallow copy

  • concat

let arr = [1,2,3,4];
let arr2 = [].concat(arr);
arr2[2]=5;
console.log(arr); //[ 1, 2, 3, 4 ]  ✔
console.log(arr2); //[ 1, 2, 5, 4 ]

When the array is not an object, it is a deep copy from the result, in the following example

let arr = [{1:1},{2:2}];
let arr2 = arr.cancat(0)
arr2[1][2]=5;


console.log(arr);  //[ { '1': 1 }, { '2': 5 } ]  ❌变成了引用
console.log(arr2); //[ { '1': 1 }, { '2': 5 } ]

When an object is in an array, it becomes a shallow copy

Summary: Deep copy is only once the array is a one-dimensional array and does not contain objects

(Recommended tutorial: JavaScript tutorial)

2. Object.assgin()

let a= {a:1,b:2};
let b= Object.assign({},a);
a.a=3;
console.log(a)  //{a: 3, b: 2}
console.log(b)  //{a: 1, b: 2}  ✔
let a= {a:1,b:{c:2}};
let b= Object.assign({},a);
a.b.c=3;
console.log(a)  //{a: 1, b: {c:3}}
console.log(b)  //{a: 1, b: {c:3}}   ❌变成了引用

Summary: Object.assgin becomes a reference solution when it comes to nesting multiple objects: use JSON.stringify() to convert to a string and then through JSON.parse() to an object

  • 3.JSON.parse(JSON.stringify())

let a= {a:1,b:{c:2}};
let b= JSON.parse(JSON.stringify(a))
a.b.c=3;
console.log(a)  //{a: 1, b: {c:3}}
console.log(b)  //{a: 1, b: {c:2}}   ✔
let school={'name':"W3Cschool编程狮",fn:function(){}};
let my = {age:{count:18},name:"W3Cschool编程狮"};
let all=JSON.parse(JSON.stringify({...school,...my}))
console.log(all);  //{'name':"W3Cschool编程狮",age:{count:18}}; //❌把fn给丢了

Summary: JSON.parse (JSON.stringify() has some limitations and loses fn.

  • 4. Handwritten deep copy

let deepClone=(obj)=>{
    if(obj==undefined) return obj;  //undefined == null
    if(obj instanceof RegExp) return new RegExp(obj);
    if(obj instanceof Date) return new Date(obj);
    if(typeof obj!=="object") return obj;
    let newObj = new obj.constructor;
    for(let key in obj){
        if(obj.hasOwnProperty(key)){
            newObj[key] = deepClone(obj[key])
        }
    }
    return newObj;
}
let obj1 = {name:{age:"10"}}
let n = deepClone(obj1)
obj1.name.age = "231"
console.log(n);  //{name:{age:"10"}}  ✔
let obj = { name:"W3Cschool编程狮" }
obj.aaa=obj
let n = deepClone(obj1)
console.log(n);  //死循环了  ❌

You can use WeakMap to solve this problem

let deepClone=(obj,hash=new WeakMap())=>{
    if(obj==undefined) return obj;  //undefined == null
    if(obj instanceof RegExp) return new RegExp(obj);
    if(obj instanceof Date) return new Date(obj);
    if(typeof obj!=="object") return obj;
    if(hash.has(obj)) return hash.get(obj);
    let newObj = new obj.constructor;
    hash.set(obj,newObj);


    for(let key in obj){
        if(obj.hasOwnProperty(key)){
            newObj[key] = deepClone(obj[key],hash)
        }
    }
    return newObj;
}

  • 5. lodash's cloneDeep

 源码地址:https://github.com/lodash/lodash/blob/86a852fe763935bb64c12589df5391fd7d3bb14d/.internal/baseClone.js

  • 6. Cloning method in vue-router source code

function clone (value) {
  if (Array.isArray(value)) {
    return value.map(clone)
  } else if (value && typeof value === 'object') {
    const res = {}
    for (const key in value) {
      res[key] = clone(value[key])
    }
    return res
  } else {
    return value
  }
}
let arr = [{1:1},{2:2},function(){}];
let arr2 = clone(arr)
arr2[1][2]=5;
console.log(arr)  //[ { '1': 1 }, { '2': 2 }, [Function (anonymous)] ]   ✔ 深拷贝
console.log(arr2); //[ { '1': 1 }, { '2': 5 }, [Function (anonymous)] ]
function extend (a, b) {
  for (const key in b) {
    a[key] = b[key]
  }
  return a
}
let b={a:1,b:{c:2}};
let a= extend({},b);
a.b.c=5;
console.log(a);  //{ a: 1, b: { c: 5 } }
console.log(b);  //{ a: 1, b: { c: 5 } }   浅拷贝

(Recommended micro-class: JavaScript micro-course)

Source: Public Number - Clown's Cabin Author: Clown

That's what W3Cschool编程狮 has to say about the perfect solution to JavaScript's deep copy, and I hope it will help you.