Shallow (copy) clone

Deep copy

Involving interview questions: What is a shallow copy? How to achieve shallow copy? What is a deep copy? How to achieve deep copy?

let a = {
  age: 1
}
let b = a
a.age = 2
console.log(b.age) // 2

Shallow copy

First of all, you can  Object.assign solve this problem. Many people think that this function is used for deep copy. In fact, it is not. It Object.assign will only copy all the attribute values ​​to the new object. If the attribute value is an object, the address is copied, so it is not a deep copy.

let a = {
  age: 1
}
let b = Object.assign({}, a)
a.age = 2
console.log(b.age) // 1

In addition, we can also ... implement shallow copy by spreading the operator 

let a = {
  age: 1
}
let b = { ...a }
a.age = 2
console.log(b.age) // 1

Usually shallow copy can solve most of the problems, but when we encounter the following situations, we may need to use deep copy

let a = {
  age: 1,
  jobs: {
    first: 'FE'
  }
}
let b = { ...a }
a.jobs.first = 'native'
console.log(b.jobs.first) // native

ps:

arr.slice(0) 
arr.concat() 
let obj2 = {... obj}

Shallow copy only solves the problem of the first layer. If there are still objects in the following values, then it is back to the original topic, and both share the same address. To solve this problem, we have to use deep copy

 

(2) Deep copy

This problem can usually be solved through  JSON.parse(JSON.stringify(object)) .

let a = {
  age: 1,
  jobs: {
    first: 'FE'
  }
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first) // FE

But this method also has limitations:

  • Will ignore undefined
  • Will ignore symbol
  • Cannot serialize function
  • Cannot resolve circularly referenced objects
let obj = {
  a: 1,
  b: {
    c: 2,
    d: 3,
  },
}
obj.c = obj.b
obj.e = obj.a
obj.b.c = obj.c
obj.b.d = obj.b
obj.b.e = obj.b.c
let newObj = JSON.parse(JSON.stringify(obj))
console.log(newObj)

If you have such a circular reference object, you will find that deep copy cannot be achieved through this method

 

When encountering a function,  undefined or  symbol , the object cannot be serialized normally

let a = {
  age: undefined,
  sex: Symbol('male'),
  jobs: function() {},
  name: 'yck'
}
let b = JSON.parse(JSON.stringify(a))
console.log(b) // {name: "yck"}

You will find that in the above cases, the method ignores the function sum  undefined .

But under normal circumstances, complex data can be serialized, so this function can solve most problems.

If the object you need to copy contains built-in types and does not contain functions, you can use MessageChannel

function structuralClone(obj) {
  return new Promise(resolve => {
    const { port1, port2 } = new MessageChannel()
    port2.onmessage = ev => resolve(ev.data)
    port1.postMessage(obj)
  })
}

var obj = {
  a: 1,
  b: {
    c: 2
  }
}

obj.b.d = obj.b

// 注意该方法是异步的
// 可以处理 undefined 和循环引用对象
const test = async () => {
  const clone = await structuralClone(obj)
  console.log(clone)
}
test()

Of course, you may want to implement a deep copy by yourself, but in fact it is very difficult to implement a deep copy. We need to consider a variety of boundary conditions, such as how the prototype chain is processed, how the DOM is processed, etc., so the deep copy we implemented here is just Simple version, and I actually recommend using  lodash's deep copy function .

function deepClone(obj){ //判断参数是不是一个对象 
let objClone = new obj.constructor(); 
if(obj && typeof obj==="object"){
 for(key in obj){
 if(obj.hasOwnProperty(key)){
 //判断ojb子元素是否为对象,如果是,递归复制 
if(obj[key]&&typeof obj[key] ==="object"){
 objClone[key] = deepClone(obj[key]); 
}else{
 //如果不是,简单复制 
objClone[key] = obj[key]; }
 } 
} 
} 
return objClone;
 }

 

Guess you like

Origin blog.csdn.net/weixin_43844696/article/details/106781708