Welcome to pay attention to my public number

The Code of Life

Interviewer: Always ask me the depth of the copy questions, read the article

If you go out for an interview, the interviewer will always ask you some amazing questions, but you have to know, today’s question is one of them, in our work, actually we often use object copy, array copy, but often ignore the principle of it, today we will explore.

Look at the beginning of this article with two questions in mind:

  • What is light copy
  • How to implement shallow copy

What is light copy

With the help of ConardLi’s following two pictures, help us better understand the meaning of both:



From the above two pictures, we can know:

Shallow copy: For example, we define a variable asobjAnd then we assign it to another variable. This process involves shallow copy problems. The other variable is just a copy of the previous variable, and the storage address of the two variables is the same. You can think of assignment as actually binding addresses together

There are two caveats:

  • Reference data types: objects, arrays, functions, etc. These copy addresses
let obj = {name: {code'Life Code'}}

let copyObj = obj



console.log(copyObj.name === obj.name) // true indicates that the same reference address is used

Copy the code
  • Basic data types: numbers, strings, booleans these are copy values
let str = "Ken"

let str1 = str



console.log(str === str1) // true but only copies the value

Copy the code

Deep copy

For example, we put our clothes in one closet, and then you buy the same clothes, and then you buy another closet for the new clothes, so that the two clothes are completely irrelevant.

Deep copy actually means this:

To make a complete copy of an object out of memory, a new area of heap memory is created to hold the new object, and modification of the new object does not affect the original object.

let obj = {name: {code'Life Code'}}



let copyObj = JSON.parse(JSON.stringify(obj))



console.log(copyObj.name === obj.name) // false indicates that the reference address is different

Copy the code

The difference between assignment and deep/shallow copy

We are comparing here with reference types:

The assignment

Assignment actually assigns the address of the object, the reference address of the array, which means that the two objects are linked, there is a relationship, whenever one variable changes, the other variable changes.

let obj = {

  name'Life Code'.

  arr: [1.2.3]

}



let obj1 = obj



obj1.name = "Ken"

obj1.arr = [4.5.6]



console.log(obj1, obj) / / obj1: {name: 'Ken, arr: [4 and 6]} obj: {name:' Ken, arr: (4 and 6)}

Copy the code

Shallow copy

When memory is created in the heap again, 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 affect each other because they share the same memory block.

/ / shallow copy

let obj1 = {

    name : 'Life Code'.

    arr : [1.2.3].

};

let obj2=shallowClone(obj1)

obj2.name = "Ken";

obj2.arr = [5.6.7];// Old and new objects still share the same memory

// This is a shallow-copy method

function shallowClone(source{

    var target = {};

    for(var i in source) {

        if (source.hasOwnProperty(i)) {

            target[i] = source[i];

        }

    }

    return target;

}

console.log('obj1',obj1) 

Obj1 {name: 'lifecode ', arr: [5,6,7]}

console.log('obj2',obj2) 

// obj2 { name: 'Ken', arr: [ 5, 6, 7 ] }

Copy the code

Deep copy

Create a new area of heap memory to store the new object, and make a recursive copy of the child objects in the object. The two objects before and after the copy do not affect each other.

/ / copy

let obj1 = {

    name : 'Life Code'.

    arr : [1.2.3].

};

let obj2=deepClone(obj1)

obj2.name = "Ken";

obj2.arr = [5.6.7];// The new object does not share memory with the original object

// This is a deep-copy method

function deepClone(obj{

    if (obj === nullreturn obj; 

    if (obj instanceof Datereturn new Date(obj);

    if (obj instanceof RegExpreturn new RegExp(obj);

    if (typeofobj ! = ="object"return obj;

    let cloneObj = new obj.constructor();

    for (let key in obj) {

      if (obj.hasOwnProperty(key)) {

        // Implement a recursive copy

        cloneObj[key] = deepClone(obj[key]);

      }

    }

    return cloneObj;

}

console.log('obj1',obj1) 

Obj1 {name: 'lifecode ', arr: [1, 2, 3]}

console.log('obj2',obj2) 

// obj2 { name: 'Ken', arr: [ 5, 6, 7 ] }

Copy the code

Shallow copy implementation

Object.assign()

let obj1 = { person: {name"kobe".age41},sports:'basketball' };

let obj2 = Object.assign({}, obj1);

obj2.person.name = "wade";

obj2.sports = 'football'

console.log(obj1); 

// { person: { name: 'wade', age: 41 }, sports: 'basketball' }

Copy the code

The _.clone method of the lodash library

var _ = require('lodash');

var obj1 = {

    a1.

    b: { f: { g1}},

    c: [1.2.3]

};

var obj2 = _.clone(obj1);

console.log(obj1.b.f === obj2.b.f);

// true

Copy the code

Expansion operator…

let obj1 = { name'Kobe'.address: {x:100.y:100}}

let obj2= {... obj1}

obj1.address.x = 200;

obj1.name = 'wade'

console.log('obj2',obj2) 

// obj2 { name: 'Kobe', address: { x: 200, y: 100 } }

Copy the code

Array.prototype.concat()

let arr = [1.3, {

    username'kobe'

}];

let arr2 = arr.concat();    

arr2[2].username = 'wade';

console.log(arr); 

//[ 1, 3, { username: 'wade' } ]

Copy the code

Array.prototype.slice()

let arr = [1.3, {

    username' kobe'

    }];

let arr3 = arr.slice();

arr3[2].username = 'wade'

console.log(arr); 

// [ 1, 3, { username: 'wade' } ]

Copy the code

Deep copy implementation

JSON.parse(JSON.stringify())

The _. CloneDeep method of the lodash library

var _ = require('lodash');

var obj1 = {

    a1.

    b: { f: { g1}},

    c: [1.2.3]

};

var obj2 = _.cloneDeep(obj1);

console.log(obj1.b.f === obj2.b.f);

// false

Copy the code

JQuery. The extend () method

var$=require('jquery');

var obj1 = {

    a1.

    b: { f: { g1}},

    c: [1.2.3]

};

var obj2 = $.extend(true, {}, obj1);

console.log(obj1.b.f === obj2.b.f); 

// false

Copy the code

Handwritten recursive method

The recursive method implements the principle of deep cloning: iterating through objects and arrays until they contain all the basic data types, and then copying, which is called deep copy.

There is a special case needs to pay attention to is the condition of the circular reference object, the object’s properties directly refer to its own situation, solve the problem of circular reference, we can open up a extra storage space, to store the current objects and copy the object correspondence, when need to copy the current object, go to the storage space, find ever copy this object, Return if there is, continue to copy if there is not, so as to cleverly solve the problem of circular reference. If in doubt about this, please read carefully how ConardLi can write a deep copy to impress the interviewer. This article.

function deepClone(obj, hash = new WeakMap()) {

  if (obj === nullreturn obj; 

  // If it is null or undefined, I will not copy it

  if (obj instanceof Datereturn new Date(obj);

  if (obj instanceof RegExpreturn new RegExp(obj);

  // May be objects or ordinary values if functions do not need deep copies

  if (typeofobj ! = ="object"return obj;

  // Make a deep copy of an object

  if (hash.get(obj)) return hash.get(obj);

  let cloneObj = new obj.constructor();

  // Find the constructor from the parent class stereotype, which points to the current class itself

  hash.set(obj, cloneObj);

  for (let key in obj) {

    if (obj.hasOwnProperty(key)) {

      // Implement a recursive copy

      cloneObj[key] = deepClone(obj[key], hash);

    }

  }

  return cloneObj;

}

let obj = { name1.address: { x100}};

obj.o = obj; // The object has a circular reference

let d = deepClone(obj);

obj.address.x = 200;

console.log(d);

Copy the code

reference

An article makes a deep and shallow copy of JavaScript

Copy the code