Basic JavaScript method of deep copy (shallow copy and deep copy), javascript depth

Source: Internet
Author: User
Tags hasownproperty

Basic JavaScript method of deep copy (shallow copy and deep copy), javascript depth

Preface

When it comes to deep copy, we must first mention the JavaScript data type. In the previous article, the basic JavaScript method-the data type is very clear, so I will not talk about it here.

You need to know that JavaScript data types are classified into basic data types and reference data types.

There is no difference between the two copies for the basic data type. We call the two copies for the reference data type.

Shortest copy

A shallow copy means that only the reference is copied, but the actual value is not copied.

const originArray = [1,2,3,4,5];const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};const cloneArray = originArray;const cloneObj = originObj;console.log(cloneArray); // [1,2,3,4,5]console.log(originObj); // {a:'a',b:'b',c:Array[3],d:{dd:'dd'}}cloneArray.push(6);cloneObj.a = {aa:'aa'};console.log(cloneArray); // [1,2,3,4,5,6]console.log(originArray); // [1,2,3,4,5,6]console.log(cloneObj); // {a:{aa:'aa'},b:'b',c:Array[3],d:{dd:'dd'}}console.log(originArray); // {a:{aa:'aa'},b:'b',c:Array[3],d:{dd:'dd'}}

The code above is the simplest use of the = value assignment operator to implement a shallow copy, you can clearly see thatcloneArrayAndcloneObjChange,originArray And originObj It also changes.

Deep copy

A deep copy is a complete copy of the target. Unlike a shallow copy, it only copies a reference layer and even the value.

As long as deep copies are made, they will not affect anyone.

Currently, there are few methods to implement deep copy, mainly in two ways:

  1. Use parse and stringify in the json object
  2. Recursion is used to re-create an object and assign values to each layer.

JSON. stringify/parse Method

Let's take a look at the two methods:

The JSON. stringify () method converts a JavaScript value to a JSON string.

JSON.stringifyIs to convert a JavaScript value into a JSON string.

The JSON. parse () method parses a JSON string, constructing the JavaScript value or object described by the string.

JSON.parseIs to convert a JSON string into a JavaScript value or object.

It's easy to understand, that is, the conversion between JavaScript values and JSON strings.

Can it implement deep copy? Let's try it.

const originArray = [1,2,3,4,5];const cloneArray = JSON.parse(JSON.stringify(originArray));console.log(cloneArray === originArray); // falseconst originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};const cloneObj = JSON.parse(JSON.stringify(originObj));console.log(cloneObj === originObj); // falsecloneObj.a = 'aa';cloneObj.c = [1,1,1];cloneObj.d.dd = 'doubled';console.log(cloneObj); // {a:'aa',b:'b',c:[1,1,1],d:{dd:'doubled'}};console.log(originObj); // {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};

It is indeed a deep copy, and it is very convenient. However, this method can only be used in some simple cases. For example, the following object is not applicable:

const originObj = { name:'axuebin', sayHello:function(){ console.log('Hello World'); }}console.log(originObj); // {name: "axuebin", sayHello: ƒ}const cloneObj = JSON.parse(JSON.stringify(originObj));console.log(cloneObj); // {name: "axuebin"}

Found in cloneObj ... Why?

The cause is found on the MDN:

If undefined, a function, or a symbol is encountered during conversion it is either omitted (when it is found in an object) or censored to null (when it is found in an array ). JSON. stringify can also just return undefined when passing in "pure" values like JSON. stringify (function () {}) or JSON. stringify (undefined ).

undefined,function,symbol Will be ignored during the conversion process...

If an object contains a function (common), you cannot use this method for deep copy.

Recursive Method

The idea of recursion is very simple, that is, to create an object for each layer of data-> assign values to an object, simply and roughly put the code:

Function deepClone (source) {const targetObj = source. constructor === Array? []: {}; // Determines whether the replication target is an array or an object for (let keys in source) {// traverses the target if (source. hasOwnProperty (keys) {if (source [keys] & typeof source [keys] = 'object') {// if the value is an object, recursion: targetObj [keys] = source [keys]. constructor === Array? []: {}; TargetObj [keys] = deepClone (source [keys]);} else {// if not, assign the value targetObj [keys] = source [keys] ;}} return targetObj;} directly ;}

Let's try:

const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};const cloneObj = deepClone(originObj);console.log(cloneObj === originObj); // falsecloneObj.a = 'aa';cloneObj.c = [1,1,1];cloneObj.d.dd = 'doubled';console.log(cloneObj); // {a:'aa',b:'b',c:[1,1,1],d:{dd:'doubled'}};console.log(originObj); // {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};

Yes. Then try again with the function:

const originObj = { name:'axuebin', sayHello:function(){ console.log('Hello World'); }}console.log(originObj); // {name: "axuebin", sayHello: ƒ}const cloneObj = deepClone(originObj);console.log(cloneObj); // {name: "axuebin", sayHello: ƒ}

Or. Done.

Do you think this is the end ?? Of course not.

COPY method in JavaScript

We know that in JavaScript, the array has two methods: concat and slice, which can be used to copy the original array. Neither of the two methods will modify the original array, returns a new modified array.

In addition, ES6 introducesObject.assgn Methods and... expansion operators can also be used to copy objects.

What about the shortest copy or deep copy?

Concat

The concat () method is used to merge two or more arrays. This method does not change the existing arrays, but instead returns a new array.

This method can connect two or more arrays, but it does not modify the existing array, but returns a new array.

It seems like a deep copy. Let's try it:

const originArray = [1,2,3,4,5];const cloneArray = originArray.concat();console.log(cloneArray === originArray); // falsecloneArray.push(6); // [1,2,3,4,5,6]console.log(originArray); [1,2,3,4,5];

It looks like a deep copy.

Let's consider a question. What if the object is multi-layered.

const originArray = [1,[1,2,3],{a:1}];const cloneArray = originArray.concat();console.log(cloneArray === originArray); // falsecloneArray[1].push(4);cloneArray[2].a = 2; console.log(originArray); // [1,[1,2,3,4],{a:2}]

originArrayContains Arrays [1,2,3] And object {a:1}If we directly modify the array and object, it will not affectoriginArrayBut we modify the Array[1,2,3]Or object {a:1}, FoundoriginArrayAlso changed.

Conclusion: concat only performs deep copy on the first layer of the array.

Slice

The slice () method returns a shallow copy of a portion of an array into a new array object selected from begin to end (end not supported DED). The original array will not be modified.

In the explanation, a shallow copy is written ~

However, it is not!

const originArray = [1,2,3,4,5];const cloneArray = originArray.slice();console.log(cloneArray === originArray); // falsecloneArray.push(6); // [1,2,3,4,5,6]console.log(originArray); [1,2,3,4,5];

Similarly, let's try arrays of multiple layers.

const originArray = [1,[1,2,3],{a:1}];const cloneArray = originArray.slice();console.log(cloneArray === originArray); // falsecloneArray[1].push(4);cloneArray[2].a = 2; console.log(originArray); // [1,[1,2,3,4],{a:2}]

Sure enough, the result is the same as that of concat.

Conclusion: slice only performs deep copy on the first layer of the array.

Object. assign ()

The Object. assign () method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.

Copy and copy.

So what about the shortest copy or the deep copy?

Try it by yourself ..

Conclusion: Object. assign () copies the attribute values. If the attribute value of the source object is a reference to the object, it only copies the reference value.

... Expansion Operator

const originArray = [1,2,3,4,5,[6,7,8]];const originObj = {a:1,b:{bb:1}};const cloneArray = [...originArray];cloneArray[0] = 0;cloneArray[5].push(9);console.log(originArray); // [1,2,3,4,5,[6,7,8,9]]const cloneObj = {...originObj};cloneObj.a = 2;cloneObj.b.bb = 2;console.log(originObj); // {a:1,b:{bb:2}}

Conclusion:... implements the deep copy of the first layer of the object. The following is only the reference value of the copy.

First-layer shortest copy

As we know, there is a situation in which we perform a deep copy on the first layer of the target object, followed by a light copy, which can be called the "first-layer light copy ".

We can implement such a function by ourselves:

Function shallowClone (source) {const targetObj = source. constructor === Array? []: {}; // Determines whether the replication target is an array or an object for (let keys in source) {// traverses the target if (source. hasOwnProperty (keys) {targetObj [keys] = source [keys] ;}} return targetObj ;}

Let's test:

const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};const cloneObj = shallowClone(originObj);console.log(cloneObj === originObj); // falsecloneObj.a='aa';cloneObj.c=[1,1,1];cloneObj.d.dd='surprise';

After modification,cloneObjNeedless to say, it must be {a: 'A', B: 'B', c: [, 1], d: {dd: 'surprise, what about originObj? We have just verified that cloneObj = originObj is false, indicating that the two objects have different reference addresses. It should be that the modified cloneObj does not affect originObj.

console.log(cloneObj); // {a:'aa',b:'b',c:[1,1,1],d:{dd:'surprise'}}console.log(originObj); // {a:'a',b:'b',c:[1,2,3],d:{dd:'surprise'}}

What happend?

In originObj, a and c are not affected, but an object in d is modified... What about deep copy? Are the referenced addresses different?

It turns out to be like this:

  1. From the shallowClone code, we can see that we only make a deep copy of the target at the first layer, and we directly use the = value assignment operator to copy the target at the beginning of the second layer.
  2. So, the target after the second layer only copies a reference, that is, a shortest copy.

Summary

  1. The value assignment operator = implements the shortest copy and only copies the reference values of objects;
  2. In JavaScript, the array and object's built-in copy methods are both "first-layer shallow copy ";
  3. JSON. stringify implements deep copy, but has requirements on the target object;
  4. If you want to perform deep copy in the true sense, apply recursion.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.