The phenomenon of

Js true shallow copy refers to reference data types.

Basic types: Number, String, Boolean, Null, Undefined, Symbol Reference types: Object, Array, Date, RegExp, Function

Reference type addresses are stored in the stack, and objects are actually stored in the heap. Js function parameters are passed by value.

The hierarchy

  • Shallow copy copies only the properties of the object sequentially, not recursively, that is, only the first-level properties of the target object are assigned.
  • Deep copy differs from shallow copy in that it copies not only the first layer properties of the target object, but all properties of the target object recursively.

Whether to open up a new heap for attributes

  • A shallow copy creates a new object with an exact copy of the original object’s property values. If the property is a primitive type, it copies the value of the primitive type, and if the property is a reference type, it copies the memory address, so if one object changes the address, it affects the other object.
  • A deep copy is a complete copy of an object from the heap, creating a new area of the heap to store the new object, and modifying the new object does not affect the original object.


Assignment, the difference between shallow copy and deep copy

  • When we assign an object to a new variable, we assign the object’s address on the stack, not the data in the heap. That is, two objects point to the same storage space. If any object is changed, it is the content of the changed storage space. Therefore, the two objects are linked.
  • Shallow copy: The basic data types of objects before and after the copy do not affect each other. However, the reference types of objects before and after the copy do affect each other because they share the same memory block.
  • Deep copy: creates a new area of heap memory to store the new object, and makes a recursive copy of the child objects in the object. The two objects before and after the copy do not affect each other.


var objOrigin = {
	name: 'Ear snail'.information: {
  	age: 27.base: 'shanghai'}}// Assign
var objAssignment = objOrigin;

/ / shallow copy
var objShallowCopy = Object.assign({}, objOrigin)

/ / copy
var objDeepCopy = JSON.parse(JSON.stringify(objOrigin))
Copy the code


The memory view











graphic


Shallow copy

way

An array of

Array.concat

let array = [1.2, {name: 'rodchen'}];
let arrayShallow = array.concat([]);

array[2].name = 'Ear snail';
console.log(arrayShallow);
Copy the code


Array.slice

let array = [1.2, {name: 'rodchen'}];
let arrayShallow = array.slice(1);

array[2].name = 'Ear snail';
console.log(arrayShallow);
Copy the code


ES6 extended operator

let array = [1.2, {name: 'rodchen'}];
let arrayShallow = [...array];

array[2].name = 'Ear snail';
console.log(arrayShallow);
Copy the code


Array.map | Array.filter

let array = [1.2, {name: 'rodchen'}];
let arrayMapShallow = array.map(item= > item);

let arrayFilterShallow = array.filter(item= > true);

array[2].name = 'Ear snail';
console.log(arrayMapShallow);
console.log(arrayFilterShallow);
Copy the code


object

Object.assign

let obj = {
	age: 27.information: {
  	name: 'rodchen'}}let shallowObj = Object.assign({}, obj)
obj.information.name = 'Ear snail'
console.log(shallowObj)
Copy the code


Object extension character

let obj = {
	age: 27.information: {
  	name: 'rodchen'}}letshallowObj = {... obj} obj.information.name ='Ear snail'
console.log(shallowObj)
Copy the code


Manual implementation

function cloneShallow(source) {
  // Determine if source is an object
  if(! (sourceinstanceof Object)) {
    return source;
  }

  var target = source instanceof Array ? [] : {};

  for (var key in source) {
    if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; }}return target;
}
Copy the code




Deep copy

way

JSON parse and Stringify methods

  • Undefined, arbitrary functions, regular expression types, and symbol values are ignored during serialization (when they appear in property values of non-array objects) or converted to NULL (when they appear in arrays);
  • It will discard the object’s constructor. After a deep copy, whatever the original constructor of this Object was, after a deep copy, it will become Object;
  • An object with a circular reference cannot be handled correctly.


Manual implementation

The initial release


function cloneDeep(source) {
  // Determine if source is an object
  if(! (sourceinstanceof Object)) {
    return source;
  }

  var target = source instanceof Array ? [] : {};

  for (var key in source) {
    if (Object.prototype.hasOwnProperty.call(source, key)) {
      target[key] = source instanceof Object? cloneDeep(source[key]) : source[key]; }}return target;
}
Copy the code
let array = [1.2, {name: 'rodchen'}];
let arrayShallow = cloneDeep(array);

array[2].name = 'Ear snail';
console.log(arrayShallow);  // Array [1, 2, Object { name: "rodchen" }]

let obj = {
  age: 27.information: {
  	name: 'rodchen'}}let shallowObj = cloneDeep(obj)
obj.information.name = 'Ear snail'
console.log(shallowObj) // Object { age: 27, information: Object { name: "rodchen" } }
Copy the code


A circular reference

In the following example, we use a loop application to perform the above method and report a stack overflow.

let array = [1.2];
array[2] = array
let arrayShallow = cloneDeep(array);  // Error: Maximum call stack size exceeded

array[2].name = 'Ear snail';
console.log(arrayShallow);

let obj = {
  age: 27,
}

obj.information = obj

let shallowObj = cloneDeep(obj)  // Error: Maximum call stack size exceeded
obj.information.name = 'Ear snail'
console.log(shallowObj)
Copy the code
function cloneDeep(source, hash = new WeakMap(a)) {
  // Determine if source is an object
  if(! (sourceinstanceof Object)) {
    return source;
  }
  
  if (hash.get(source)) return hash.get(source);
  
  var target = source instanceof Array ? [] : {};
  hash.set(source, target);

  for (var key in source) {
    if (Object.prototype.hasOwnProperty.call(source, key)) {
      target[key] = source instanceof Object? cloneDeep(source[key], hash) : source[key]; }}return target;
}
Copy the code

The weakMap here can be replaced by the ES5 array.


Match method, date, re

function cloneDeep(source, hash = new WeakMap(a)) {
  // Determine if source is an object
  if(! (sourceinstanceof Object)) {
    return source;
  }
  
  if (source instanceof Function) return new Function("return " + source.toString())();
  if (source instanceof Date) return new Date(source);
  if (source instanceof RegExp) return new RegExp(source);
  
  if (hash.get(source)) return hash.get(source);
  
  var target = source instanceof Array ? [] : {};
  hash.set(source, target);

  for (var key in source) {
    if (Object.prototype.hasOwnProperty.call(source, key)) {
      target[key] = source instanceof Object? cloneDeep(source[key], hash) : source[key]; }}return target;
}
Copy the code


The third party

  • The Underscore — _. Clone () :
This method is actually a shallow copyCopy the code
  • JQuery –.clone()/.clone() /.clone() /.extend():
JQuery also has one called $.clone(), but it is not used for deep copy of ordinary JS objects, but for DOM objects. Similar to Underscore, we can do deep replication using the $.extend() method. Thankfully, we can implement recursive extend in jQuery by adding a parameter. Call $. The extend (true, {},...). You can do deep copy.Copy the code
  • Lodash — _.clone() / _.clonedeep ():
There are two replication methods in Lodash, _.clone() and _.clonedeep (). The _. Clone (obj,true) equivalent to _. CloneDeep (obj)Copy the code
// npm install --save @jsmini/clone
import { clone, cloneJSON, cloneLoop, cloneForce } from '@jsmini/clone';
Copy the code




With reference to

Segmentfault.com/a/119000001… Segmentfault.com/a/119000001… Jerryzou.com/posts/dive-… Juejin. Cn/post / 684490…