Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Detailed introduction of deep copy and shallow copy in JavaScript

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly introduces "the detailed introduction of deep copy and shallow copy in JavaScript". In daily operation, I believe that many people have doubts about the detailed introduction of deep copy and shallow copy in JavaScript. The editor consulted all kinds of materials and sorted out simple and easy-to-use operation methods. I hope it will be helpful to answer the questions of "detailed introduction of deep copy and shallow copy in JavaScript". Next, please follow the editor to study!

Before talking about deep copy and shallow copy, let's look at two simple cases:

/ / case 1 var num1 = 1, num2 = num1; console.log (num1) / / 1 console.log (num2) / / 1 num2 = 2; / / modify num2 console.log (num1) / / 1 console.log (num2) / / 2 / / case 2 var obj1 = {x: 1, y: 2}, obj2 = obj1 Console.log (obj1) / / {x: 1, y: 2} console.log (obj2) / / {x: 1, y: 2} obj2.x = 2; / / modify obj2.x console.log (obj1) / / {x: 2, y: 2} console.log (obj2) / / {x: 2, y: 2}

According to conventional thinking, obj1, like num1, will not change with the change of another value, while the obj1 here changes with the change of obj2. It is also a variable, why does it behave differently? This introduces the concepts of basic types and reference types in JS.

Basic types and reference types

The ECMAScript variable may contain values of two different data types: basic type values and reference type values. Basic type values refer to simple segments of data that are stored in stack memory, that is, a location where the value is completely stored in memory. Reference type values refer to objects that hold objects in heap memory, meaning that what is actually stored in a variable is just a pointer to another location in memory where the object is stored.

For example, the difference in assignment between the basic type and the reference type can be understood in terms of "chain store" and "single store": the basic type assignment is equal to the standard of installing chain stores in a new place to open a new branch store. The new store is independent of other old stores and operates separately. The reference type assignment is equivalent to two keys in a store, which are managed by two bosses at the same time, and the behavior of both bosses may affect the operation of a store.

The above clearly introduces the definition and difference between basic types and reference types. At present, the basic types are:

Boolean, Null, Undefined, Number, String, Symbol. Reference types are: Object, Array, Function. The reason for saying "at present" is that Symbol is just coming out of ES6, and there may be new types coming out later.

Going back to the previous case, the value in case 1 is the basic type, and the value in case 2 is the reference type. The assignment in case 2 is a typical shallow copy, and the concepts of deep copy and shallow copy only exist in the reference type.

Deep copy and shallow copy

Now that we know the origin of deep copy and shallow copy, how to achieve deep copy? Let's first see if the native methods of Array and Object support:

Array

Var arr1 = [1,2], arr2 = arr1.slice (); console.log (arr1); / / [1,2] console.log (arr2); / / [1,2] arr2 [0] = 3; / / modify arr2 console.log (arr1); / / [1,2] console.log (arr2); / / [3,2]

At this point, the modification of arr2 does not affect arr1, so it seems that the implementation of deep copy is not that difficult. Let's change arr1 to a two-dimensional array and take a look:

Var arr1 = [1,2, [3,4]], arr2 = arr1.slice (); console.log (arr1); / / [1,2, [3,4]] console.log (arr2); / / [1,2, [3,4]] arr2 [2] [1] = 5; console.log (arr1); / / [1,2, [3,5]] console.log (arr2); / / [1,2, [3,5]

Why, arr2 has changed arr1 again, and it seems that slice () can only implement a deep copy of an one-dimensional array.

Also have the same features: concat, Array.from ().

Object

1. Object.assign ()

Var obj1 = {x: 1, y: 2}, obj2 = Object.assign ({}, obj1); console.log (obj1) / / {x: 1, y: 2} console.log (obj2) / / {x: 1, y: 2} obj2.x = 2 / / modify obj2.x console.log (obj1) / / {x: 1, y: 2} console.log (obj2) / / {x: 2, y: 2} var obj1 = {x: 1, y: {m: 1}}; var obj2 = Object.assign ({}, obj1) Console.log (obj1) / / {x: 1, y: {m: 1}} console.log (obj2) / / {x: 1, y: {m: 1}} obj2.y.m = 2; / / modify obj2.y.m console.log (obj1) / / {x: 1, y: {m: 2}} console.log (obj2) / / {x: 2, y: {m: 2}}

After testing, Object.assign () can only achieve a deep copy of one-dimensional objects.

2. JSON.parse (JSON.stringify (obj))

Var obj1 = {x: 1, y: {m: 1}}; var obj2 = JSON.parse (JSON.stringify (obj1)); console.log (obj1) / / {x: 1, y: {m: 1}} console.log (obj2) / / {x: 1, y: {m: 1}} obj2.y.m = 2 / / modify obj2.y.m console.log (obj1) / / {x: 1, y: {m: 1}} console.log (obj2) / / {x: 2, y: {m: 2}}

JSON.parse (JSON.stringify (obj)) looks good, but the description of the MDN document has a sentence that is clear:

Undefined, arbitrary functions, and symbol values are ignored during serialization (when they appear in the property values of non-array objects) or converted to null (when they appear in the array).

Let's transform obj1 again:

Var obj1 = {x: 1, y: undefined, z: function add (Z1, Z2) {return Z1 + Z2}, a: Symbol ("foo")}; var obj2 = JSON.parse (JSON.stringify (obj1)); console.log (obj1) / / {x: 1, y: undefined, z: Symbol (foo)} console.log (JSON.stringify (obj1)) / / {"x": 1} console.log (obj2) / / {x: 1}

It is found that during the JSON.stringify () serialization of obj1, y, z, and an are all ignored, which validates the description of the MDN document. In this case, the use of JSON.parse (JSON.stringify (obj)) is also limited. Objects containing undefined, function and symbol values cannot be copied deeply, but JSON.parse (JSON.stringify (obj)) is simple and rough and meets 90% of the usage scenarios.

After verification, we find that the own method provided by JS can not completely solve the problem of deep copy of Array and Object. Can only offer a mass killer: recursion

Function deepCopy (obj) {/ / create a new object let result = {} let keys = Object.keys (obj), key = null, temp = null; for (let I = 0; I < keys.length; iTunes +) {key = keys [I]; temp = obj [key] / / if the value of the field is also an object, the recursive operation if (temp & & typeof temp = = 'object') {result [key] = deepCopy (temp);} else {/ / otherwise directly assign to the new object result [key] = temp;}} return result } var obj1 = {x: {m: 1}, y: undefined, z: function add (Z1, Z2) {return Z1 + Z2}, a: Symbol ("foo")}; var obj2 = deepCopy (obj1); obj2.x.m = 2; console.log (obj1) / / {x: {m: 1}, y: undefined, z: obj2, a: Symbol (foo)} console.log (obj2); / / {x: {m: 2}, y: undefined, z: foo, a: Symbol (foo)}

As you can see, recursion solves all the problems left over, and we can also use third-party libraries: jquery's $.extend and lodash's _ .cloneDeep to solve deep copies. Although the above is validated with Object, it also applies to Array, because Array is also a special Object.

At this point, the deep copy problem can basically come to an end. However, there is also a very special scenario:

Circular reference copy

Var obj1 = {x: 1, y: 2}; obj1.z = obj1; var obj2 = deepCopy (obj1)

At this point, if you call the deepCopy function just now, it will fall into a recursive process of a loop, resulting in a stack explosion. Jquery's $. Extend didn't solve it either. Solving this problem is also very simple, you only need to determine whether the field of an object refers to the object or any parent of the object, and modify the code:

Function deepCopy (obj, parent = null) {/ / create a new object let result = {}; let keys = Object.keys (obj), key = null, temp= null, _ parent = parent / / if the field has a parent, you need to trace the parent of the field while (_ parent) {/ / if the field references its parent, it is a circular reference if (_ parent.originalParent = obj) {/ / the circular reference directly returns the new object of the same level return _ parent.currentParent;} _ parent = _ parent.parent } for (let I = 0; I < keys.length; iTunes +) {key = keys [I]; temp= obj [key] / / if the value of the field is also an object if (temp & & typeof temp=== 'object') {/ / Recursive deep copy passes the same-level object to be copied and the new object to parent for easy traceability circular reference result [key] = DeepCopy (temp, {originalParent: obj, currentParent: result Parent: parent}) } else {result [key] = temp;}} return result;} var obj1 = {x: 1, y: 2}; obj1.z = obj1; var obj2 = deepCopy (obj1); console.log (obj1); / / too long to go to the browser to try ~ console.log (obj2) / / it's too long to go to the browser and try it. At this point, the study on "detailed introduction to deep and shallow copies in JavaScript" is over. I hope you can solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report