A brief discussion on JavaScript shallow copy and deep copy

A brief discussion on JavaScript shallow copy and deep copy

There are a lot of discussions about this topic on the Internet. I sorted them out myself according to various situations. In the end, I was able to achieve deep copy almost perfectly. Everyone is welcome to discuss.

Objects in javascript are reference types. When copying objects, you need to consider whether to use shallow copy or deep copy.

1. Direct assignment

An object is a reference type. If it is directly assigned to another object, it is just a reference. In fact, the two variables point to the same data object. If the properties of one object change, the other one will also change.

Example 1, simple example:

let human1 = {
    id: 1,
    name: "happy"
};
human2 = human1; // Here is a direct assignment console.log(human1); // {id: 1, name: 'happy'}
console.log(human2); // {id: 1, name: 'happy'}
 
// Changing human1's name will also change human2's human1.name = "life";
console.log(human1); // {id: 1, name: 'life'}
console.log(human2); // {id: 1, name: 'life'}

Example 2: passing an object as a parameter also passes a reference:

let human1 = {
    id: 1,
    name: "happy"
};
 
console.log(human1); // {id: 1, name: 'happy'}
 
function foo(human) {
    // The name of the human object is changed here human.name = "life";
}
foo(human1); // passing an object is by reference console.log(human1); // {id: 1, name: 'life'}

2. Shallow Copy

A shallow copy only copies the first layer of the object. If the property value of the first layer is an object, then only a reference to the property is copied.

let object1 = {
    a: 1,
    b: { // b is an object b1: 2
    }
};
object2 = Object.assign({}, object1); // This is a shallow copy, where only the reference of object b is copied // a is a regular type and will not affect each other object1.a = 10;
console.log(object1.a); // 10
console.log(object2.a); // 1
 
// b is an object, which will affect each other object1.b.b1 = 20;
console.log(object1.b.b1); // 20
console.log(object2.b.b1); // 20


If you want to achieve a complete copy, you must use a deep copy.

3. Deep Copy

Sen copy means that not only one layer needs to be copied, but also the layers inside if they are objects need to be copied.

1. JSON object method

If the object can be confirmed to be a JSON object, then it can be used in the JSON object format.

Using the example above:

let object1 = {
    a: 1,
    b: { // b is an object b1: 2
    }
};
 
object2 = JSON.parse(JSON.stringify(object1)); // Deep copy // a is a regular type and will not affect each other object1.a = 10;
console.log(object1.a); // 10
console.log(object2.a); // 1
 
// b is an object and will not affect each other object1.b.b1 = 20;
console.log(object1.b.b1); // 20
console.log(object2.b.b1); // 2


The principle of deep copy here is actually to convert the object into a json string first, and then into json object. After being converted into a json string, it has nothing to do with the original object.

Advantages of this method: It is very simple to implement.

shortcoming:

If any attribute value is a function, it cannot be copied and the data will be lost.
In addition, prototype objects cannot be copied.

Therefore, this method is only suitable for objects that are confirmed to be pure json data.

2. Recursive copy

Because we need to copy layer by layer, it is easy to think of using a recursive approach, refer to the following implementation:

function deepCopy(source) {
    // If it is not an object or null, return directly if (typeof source !== 'object' || source === null) {
        return source;
    }
 
    let target = {};
    // Traverse and copy properties for (let k in source) {
        if (!source.hasOwnProperty(k)) {
            continue;
        }
 
        if (typeof source[k] === 'object') { // If it is an object, recursively copy target[k] = deepCopy(source[k]);
            continue;
        }
 
        let descriptor = Object.getOwnPropertyDescriptor(source, k);
        Object.defineProperty(target, k, descriptor);
    }
 
    return target;
}

Because the objects are copied layer by layer, the two objects will not affect each other after the copying is completed, and methods can also be supported.

let object1 = {
    a: 1,
    b: { // b is an object b1: 2
    },
    f: function() { // f is a method console.log(3);
    }
};
object2 = deepCopy(object1); // Deep copy, you can also copy functions.
object1.f(); // 3
object2.f(); // 3
 
// b is an object and will not affect each other object1.b.b1 = 20;
console.log(object1.b.b1); // 20
console.log(object2.b.b1); // 2


Copying prototype objects

But there is still a problem with this method, that is, the prototype object cannot be copied. Let's improve it a little bit:

// Change let target = {}; to the following // to ensure that the prototype is also copied let target = Object.create(Object.getPrototypeOf(source));


That's it, let's verify it with an example:

function Human() {
    this.id = 1;
}
Human.prototype.bar = function() {
    console.log("bar");
};
 
let human1 = new Human();
human2 = deepCopy(human1);
 
console.log("human1", human1);
console.log("human2", human2);


Look at the prototypes of the next two objects:

Deep copy the prototype object:

Perfect copy.

Of course, there is a problem with this method. If the recursion level is too deep, it may easily cause stack overflow. However, in practice it is also recommended not to copy very large objects, there should be other good solutions.

This is the end of this article about JavaScript shallow copy and deep copy. For more relevant JavaScript shallow copy and deep copy content, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope you will support 123WORDPRESS.COM in the future!

Reference Documents:

JS implements deep copy: https://www.cnblogs.com/dobeco/p/11295316.html
Object.assign(): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
Object.create(): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create
Object.getPrototypeOf(): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf
Object.defineProperty(): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
Object.getOwnPropertyDescriptor(): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor
hasOwnProperty(): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty

You may also be interested in:
  • Detailed explanation of deep copy and shallow copy in JavaScript
  • Detailed description of shallow copy and deep copy in js
  • Detailed explanation of JS variable storage deep copy and shallow copy
  • JS object copying (deep copy and shallow copy)
  • Commonplace talk about JavaScript deep copy and shallow copy

<<:  MySQL infobright installation steps

>>:  Five solutions to cross-browser problems (summary)

Recommend

Vue3 (Part 2) Integrating Ant Design Vue

Table of contents 1. Integrate Ant Design Vue 2. ...

When MySQL is upgraded to 5.7, WordPress reports error 1067 when importing data

I recently upgraded MySQL to 5.7, and WordPress r...

HTML table markup tutorial (9): cell spacing attribute CELLSPACING

A certain distance can be set between cells in a ...

Making a simple game engine with React Native

Table of contents Introduction Get started A brie...

MySQL view principles and basic operation examples

This article uses examples to illustrate the prin...

CSS injection knowledge summary

Modern browsers no longer allow JavaScript to be ...

Ideas for creating wave effects with CSS

Previously, I introduced several ways to achieve ...

How to get the width and height of the image in WeChat applet

origin Recently, I am working on requirement A, i...

Example of how to deploy Spring Boot using Docker

Here we mainly use spring-boot out of the box, wh...

CSS3 realizes text relief effect, engraving effect, flame text

To achieve this effect, you must first know a pro...

Detailed explanation of docker visualization graphics tool portainer

Table of contents 1. Introduction to Portainer 2....