Delve deeper into how JavaScript achieves deep cloning

Source: Internet
Author: User
Tags shallow copy hasownproperty

In code reuse mode, there is a "copy attribute pattern" (copying properties). When it comes to code reuse, it's possible to think of code inheritance (inheritance), but it's important to remember its final goal--we'll reuse the code. Inheritance is just a means of implementing code reuse, not the only way. Copying a property is also a reuse pattern, which is different from inheritance. In this mode, the object gets the member from another object, by simply copying it . As with jquery, it has a $.extend () method that can be used to replicate properties in addition to third-party plugins. Let's take a look at a extend () function implementation Code (note here is not the source of jquery, just a simple example):

functionExtend (parent, child) {vari; //If you do not pass in the second parameter , child    //then create a new objectChild = Child | | {}; //Traverse all properties of a parent object    //and filter the properties on the prototype    //then copy the properties of itself onto the child object     for(Iinchparent) {        if(Parent.hasownproperty (i)) {Child[i]=Parent[i]; }    }    //returns the target object child    returnChild ;}

The above code is a simple implementation that iterates through the members of the parent object and copies it to the child object. Let's use the Extend () method above to test it:

var dad = {name: "Adam"}; var kid =//Adam

We found that the extend () method is working properly. But there is a problem, given above is a so-called shallow copy (shallow clone). When you use shallow copy, if you change the properties of a child object and it happens to be an object, this action also modifies the parent object, which is not the result we want in many cases alone . Consider the following scenarios:

var dad = {    counts: [1, 2, 3],    true}}; var // call the Extend () method to copy the properties of Dad to Kid // Append 4 to the kid.counts array // [1, 2, 3, 4]

From the above example, we will find that after modifying the Kid.counts property (appending the element 4), the dad.counts will also be affected. this is because when using shallow copy, because objects are passed by reference, Kid.counts and dad.counts point to the same array (or in memory they point to the same heap address).

Next, let's modify the Extend () function to achieve deep replication. all we need to do is check every property of the parent object, and if that property happens to be an object, then recursively copy the property of that object. In addition, it is necessary to detect whether the object is an array, because the literal creation of the array is different from the object's literal creation, which is [] and the latter is {}. The detection array can be detected using the Object.prototype.toString () method, which, if it is an array, returns "[Object array]". Let's take a look at the deep copy version of the Extend () function:

functionExtenddeep (parent, child) { Child= Child | | {};  for(varIinchparent) {        if(Parent.hasownproperty (i)) {//detects whether the current property is an object            if(typeofParent[i] = = = "Object") {                //if the current property is an object, also to detect if it is an array                //This is because the literal representation of the array and the literal representation of the object are different                //The former is [], and the latter is {}Child[i] = (Object.prototype.toString.call (parent[i]) = = = "[Object Array]")? [] : {}; //Recursive call ExtendExtenddeep (Parent[i], child[i]); } Else{Child[i]=Parent[i]; }        }    }    returnChild ;}

Well, the deep copy of the function has been written, the following test to see if you can expect to work, that is, whether deep replication can be achieved:

varDad ={counts: [1, 2, 3], reads: {paper:true}};varKid =Extenddeep (dad);//Modify kid's counts property and reads propertyKid.counts.push (4); Kid.reads.paper=false; Console.log (kid.counts);//[1, 2, 3, 4]Console.log (Kid.reads.paper);//falseConsole.log (dad.counts);//[1, 2, 3]Console.log (Dad.reads.paper);//true

From the above example, we can find that even if we modify the kid.counts and kid.reads of the child objects, the dad.counts and kid.reads of the parent object are not changed, so our purpose is implemented.

Here's a summary of the basic ideas for implementing deep replication:

1. Detect if the current property is an object

2. Because the array is a special object, it is also necessary to detect if the property is an array if it is an object.

3. If it is an array, create an empty array, otherwise create an {} empty object and assign the value to the current property of the child object. The Extenddeep function is then called recursively .

The above example allows us to use the recursive algorithm to implement a deep replication method. In fact, the two methods provided by ES5 's new JSON object also allow for deep copying, json.stringify () and Json.parse (), which convert the object to a string, while the latter converts the string into an object. Here we use this method to implement a deep copy of the function:

functionExtenddeep (parent, child) {varI, proxy; Proxy= Json.stringify (parent);//Convert a Parent object to a stringProxy = Json.parse (proxy)//converts a string to an object, which is a copy of the parent Child= Child | | {};  for(Iinchproxy) {        if(Proxy.hasownproperty (i)) {Child[i]=Proxy[i]; }} Proxy=NULL;//because proxy is an intermediate object, it can be recycled    returnChild ;}

Here are the test examples:

varDad ={counts: [1, 2, 3], reads: {paper:true}};varKid =Extenddeep (dad);//Modify kid's counts property and reads propertyKid.counts.push (4); Kid.reads.paper=false; Console.log (kid.counts);//[1, 2, 3, 4]Console.log (Kid.reads.paper);//falseConsole.log (dad.counts);//[1, 2, 3]Console.log (Dad.reads.paper);//true

The test found that it also enables deep replication. It is generally recommended to use this method, since Json.parse and json.stringify are built-in functions that can be processed faster. In addition, the previous method uses recursive invocation, and we all know that recursion is a low-efficiency algorithm.

Well, it's written here about the deep copy. I am also learning while summing up here, if there are errors, please ask.

Drill down into how JavaScript achieves deep cloning

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.