There is a type of code reuse mode called "copying properties pattern". When it comes to code reuse, it is very likely that the inheritance of the code comes to mind, but it is important to remember its ultimate goal - we need to reuse the code. Inheritance is just a means to implement code reuse, not the only way. Copying attributes are also a reuse mode, which is different from inheritance. In this pattern, the object will get members from another object by simply copying it. Anyone who has used jQuery knows that it has a $.extend() method, which can be used to copy properties in addition to extending third-party plug-ins. Let's take a look at the implementation code of the extend() function (note that the source code of jQuery is not just a simple example):
function extend(parent, child) { var i; //If the second parameter child is not passed in// Then create a new objectchild = child || {}; //Transfer all properties of parent object// And filter the properties on the prototype// Then copy your own attributes to the child objectfor(i in parent) { if((i)) { child[i] = parent[i]; } } //Return to the target object childreturn child; }
The above code is a simple implementation that only iterates over the members of the parent object and copies them into the child object. Let's use the extend() method above to test it:
var dad = {name: "Adam"}; var kid = extend(dad); (); //Adam
We found that the extend() method can already work properly. But there is a problem, the above is a so-called shallow clone. When using shallow copy, if the attribute of the child object is changed and the attribute happens to be another object, then this operation will also modify the parent object. In many cases, this is not the result we want. Consider the following situations:
var dad = { counts: [1, 2, 3], reads: {paper: true} }; var kid = extend(dad) //Call extend() method to copy the dad attribute to kid(4); //Add 4 into the array(); //[1, 2, 3, 4]
Through the above example, we will find that after modifying the attribute (appending element 4 into it), it will also be affected. This is because when using shallow copy, since objects are passed by reference, that is, they 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 copy. What we need to do is check every property of the parent object. If the property happens to be an object, then recursively copy the properties of the object. In addition, it is also necessary to detect whether the object is an array, because the literal creation method of the array is different from the literal creation method of the object. The former is [] and the latter is {}. The detection array can be detected using the() method. If it is an array, it will return "[object Array]". Let's take a look at the deep copy version of extend() function:
function extendDeep(parent, child) { child = child || {}; for(var i in parent) { if((i)) { //Detect whether the current attribute is an objectif(typeof parent[i] === "object") { //If the current property is an object, you must also check whether it is an array//This is because the literal representation of the array is different from the literal representation of the object//The former is [], while the latter is {}child[i] = ((parent[i]) === "[object Array]") ? [] : {}; //Recursively call extendextendDeep(parent[i], child[i]); } else { child[i] = parent[i]; } } } return child; }
OK, the deep copy function has been written. Let's test whether it can work like this, that is, whether deep copy can be achieved:
var dad = { counts: [1, 2, 3], reads: {paper: true} }; var kid = extendDeep(dad); //Modify the counts attribute and reads attribute of kid(4); = false; (); //[1, 2, 3, 4] (); //false (); //[1, 2, 3] (); //true
Through the above example, we can find that even if the sum of the child object is modified, the sum of the parent object has not changed, so our purpose is achieved.
Let’s summarize the basic ideas for realizing deep replication:
1. Detect whether the current attribute is an object
2. Because array is a special object, it is also necessary to check whether it is an array if the property is an object.
3. If it is an array, create an empty array of [], otherwise, create an empty object {} and assign it to the current attribute of the child object. Then, the extendDeep function is called recursively.
The above example enables us to implement a deep replication method using a recursive algorithm. In fact, the two methods provided by the JSON object added by ES5 can also implement deep copying, namely () and (); the former is used to convert objects into strings, while the latter converts strings into objects. Here we use this method to implement a deep copy function:
function extendDeep(parent, child) { var i, proxy; proxy = (parent); //Convert parent object to stringproxy = (proxy) //Convert string to object, this is a copy of parentchild = child || {}; for(i in proxy) { if((i)) { child[i] = proxy[i]; } } proxy = null; //Because proxy is an intermediate object, it can be recycledreturn child; }
Here is a test example:
var dad = { counts: [1, 2, 3], reads: {paper: true} }; var kid = extendDeep(dad); //Modify the counts attribute and reads attribute of kid(4); = false; (); //[1, 2, 3, 4] (); //false (); //[1, 2, 3] (); //true
Tests found that it also implements deep replication. It is generally recommended to use the latter method because the sum is a built-in function and will be faster to process. In addition, the previous method uses recursive calls, and we all know that recursion is a relatively inefficient algorithm.
I will introduce so much to you about the implementation method of deep clone in JavaScript, and I hope it will be helpful to you!