Shallow copy and deep copy

  Front end, html, javascript, node.js, Programmer

I. data types

Data is divided into basic data types (string, number, boolean, null, undefined, Symbol) and object data types.

  • Characteristics of basic data types: data stored directly in the stack
  • Features of Reference Data Types:What is stored is that the object is referenced in the stack, and the real data is stored in the heap memory.

The reference data type stores a pointer in the stack that points to the starting address of the entity in the heap. When the interpreter looks for the reference value, it first retrieves its address in the stack and obtains the entity from the heap after obtaining the address.

II. Shallow Copy and Deep Copy

Deep copy and shallow copy are only for reference data types such as Object and Array.

Schematic diagrams of deep copy and shallow copy are roughly as follows:

Shallow copy only copies the pointer to an object, not the object itself. The old and new objects still share the same memory. However, deep copy will create another identical object. The new object does not share memory with the original object. Modifying the new object will not change the original object.

Third, the difference between assignment and shallow copy

  • When we assign an object to a new variable,What is assigned is actually the address of the object in the stack, not the data in the heap.. That is, the two objects point to the same storage space. No matter which object changes, it is actually the content of the changed storage space. Therefore, the two objects are linked.
  • A shallow copy is a bitwise copy of an object,It creates a new objectThis object has an exact copy of the original object’s attribute value. If the attribute is of the basic type, the value of the basic type is copied. If the attribute is a memory address (reference type), the memory address is copied, so if one of the objects changes the address, the other object will be affected. That is, the default copy constructor only makes a shallow copy copy of the object (one member by one member in turn), that is, only copies the object space but not the resources.

Let’s look at two examples first. What changes will be brought to the original object by comparing assignment and shallow copy?

//Object Assignment
 var obj1 = {
 'name' : 'zhangsan',
 'age' :  '18',
 'language' : [1,[2,3],[4,5]],
 };
 var obj2 = obj1;
 obj2.name = "lisi";
 Obj2.language[1] = ["two", "three"];
 console.log('obj1',obj1)
 console.log('obj2',obj2)

//light copy
 var obj1 = {
 'name' : 'zhangsan',
 'age' :  '18',
 'language' : [1,[2,3],[4,5]],
 };
 var obj3 = shallowCopy(obj1);
 obj3.name = "lisi";
 Obj3.language[1] = ["two", "three"];
 function shallowCopy(src) {
 var dst = {};
 for (var prop in src) {
 if (src.hasOwnProperty(prop)) {
 dst[prop] = src[prop];
 }
 }
 return dst;
 }
 console.log('obj1',obj1)
 console.log('obj3',obj3)


In the above example, obj1 is the original data, obj2 is obtained by assignment operation, and obj3 is obtained by shallow copy. We can clearly see the impact on the original data, please refer to the following table:

IV. Implementation of Shallow Copy

1.Object.assign()

The Object.assign () method can copy any number of enumerable attributes of the source object itself to the target object, and then return the target object. However, Object.assign () makes a shallow copy, which refers to the attributes of the object, not the object itself.

var obj = { a: {a: "kobe", b: 39} };
 var initalObj = Object.assign({}, obj);
 initalObj.a.a = "wade";
 console.log(obj.a.a);  //wade

Note:When object has only one layer, it is a deep copy.

let obj = {
 username: 'kobe'
 };
 let obj2 = Object.assign({},obj);
 obj2.username = 'wade';
 console.log(obj);  //{username: "kobe"}

2.Array.prototype.concat()

let arr = [1, 3, {
 username: 'kobe'
 }];
 let arr2=arr.concat();
 arr2[2].username = 'wade';
 console.log(arr);

Modifying the new object will change to the original object:

3.Array.prototype.slice()

let arr = [1, 3, {
 username: ' kobe'
 }];
 let arr3 = arr.slice();
 arr3[2].username = 'wade'
 console.log(arr);

Similarly, modifying the new object will change to the original object:


Supplementary Notes on slice and concat Methods of Array: Array’s slice and concat methods do not modify the original array, but only return a new array with a shallow copy of the elements in the original array.

The elements of the original array will be copied according to the following rules:

  • If the element is an object reference (not an actual object), slice copies the object reference into the new array. Both object references refer to the same object. If the referenced object changes, this element in the new and original arrays will also change.
  • For Strings, Numbers, and Boolean values (not string, number, or boolean objects), slice copies these values into the new array. Modifying these strings or numbers or boolean values in another array will not affect the other array.

Perhaps this passage is difficult to understand. Let’s give an example and revise the above example slightly:

let arr = [1, 3, {
 username: ' kobe'
 }];
 let arr3 = arr.slice();
 arr3[1] = 2
 console.log(arr,arr3);

V. Implementation of Deep Copy

1.JSON.parse(JSON.stringify())

let arr = [1, 3, {
 username: ' kobe'
 }];
 let arr4 = JSON.parse(JSON.stringify(arr));
 arr4[2].username = 'duncan';
 console.log(arr, arr4)


Principle: Use JSON.stringify to convert an object into a JSON string, and then use JSON.parse () to parse the string into an object. As a result, a new object is generated, and the object will open up a new stack to realize deep copy.

Although this method can realize deep copy of arrays or objects, it cannot handle functions.

let arr = [1, 3, {
 username: ' kobe'
 },function(){}];
 let arr4 = JSON.parse(JSON.stringify(arr));
 arr4[2].username = 'duncan';
 console.log(arr, arr4)


This is because the JSON.stringify () method converts a JavaScript value (object or array) into a JSON string and cannot accept functions

2. Handwriting Recursive Method

Recursive Method to Realize Deep Cloning Principle;Traversing objects and arrays until they are all basic data types, and then copying them is depth copying.

//Define the function of detecting data type
 function checkedType(target) {
 return Object.prototype.toString.call(target).slice(8, -1)
 }
 //Implement Deep Cloning-Objects/Arrays
 function clone(target) {
 //Judge the copied data type
 //Initialize variable result to become final cloned data
 let result, targetType = checkedType(target)
 if (targetType === 'Object') {
 result = {}
 } else if (targetType === 'Array') {
 result = []
 } else {
 return target
 }
 //Traverse the target data
 for (let i in target) {
 //Get every value that traverses the data structure.
 let value = target[i]
 //Judge whether each value in the target structure has an object/array
 if (checkedType(value) === 'Object' ||
 Checked type (value) = = =' array') {//object/array is nested in the object/array
 //Continue traversing to obtain the value value
 result[i] = clone(value)
 } else {// the value obtained is a basic data type or a function.
 result[i] = value;
 }
 }
 return result
 }

3. function library lodash

The library also provides _. clonedep for Deep Copy.

var _ = require('lodash');
 var obj1 = {
 a: 1,
 b: { f: { g: 1 } },
 c: [1, 2, 3]
 };
 var obj2 = _.cloneDeep(obj1);
 console.log(obj1.b.f === obj2.b.f);
 // false

The starting address of the article isMy GitHub blog, please pay attention!

Reference article

What are js Deep Copy and Shallow Copy and Their Implementation

JavaScript shallow copy and deep copy

Js deep copy vs shallow copy

The ultimate exploration of deep copy (99% of people don’t know)