In the actual programming process, sometimes we will encounter a situation: When you have an object A, at a certain moment, a has already saved the corresponding attribute value, and the values themselves are valid, this time may require a exactly the same object B, and when the value of the property in B changes, The property values in a are not affected and can be understood to be independent of A and B, but the initialization of B is not the initialization of the object we normally create, and B's initialization data is entirely from a.
First, shallow copy
We typically do this when we need to copy an object to another object.
function Shadowcopy (source,target) {
var target=target| | {};
for (var i in source)
{
target[i]=source[i];
return
target;
}
var a={name: ' Lily ', age:19};
var b=shadowcopy (a);//b={name: ' Lily ', age:19}
The problem with a shallow copy is that if the parent object's property equals an array or another object, the child object actually gets just a memory address, not a real copy, and the child object's corresponding property changes when the parent object's array or object property changes
function Shadowcopy (source,target) {
var target=target| | {};
for (var i in source)
{
target[i]=source[i];
return
target;
}
var a={name: ' Lily ', hobbies:[' Music ', ' Sport ']};
var b=shadowcopy (a);//b={name: ' Lily ', hobbies:[' Music ', ' Sport '}
a.hobbies.push (' Read ');//b={name: ' Lily ', hobbies:[' Music ', ' Sport ', ' Read '}
Second, deep copy
In order to solve the above problem, we need to make a deep copy of the object's array and object properties. Its implementation is not difficult, as long as the recursive call "shallow copy" on the line
Function deepcopy (source,target) { var target=target| |
{}; for (var i in source) { if (typeof source[i] === ' object ') { target[i] = (source[i].constructor === array )
? [] : {} ;
deepcopy (Source[i],target[i]); }else{
target[i]=source[i]; } return
Target } var a={name: ' Lily ', Hobbies
: [' Music ', ' Sport ']}; Var b=deepcopy (a);//b={name: ' Lily ', Hobbies:[' music ', ' Sport ']} a.hobbies.push (' read ')//b={name: ' Lily ', hobbies:[' music ', ' sport ', ' read ']},b={name: ' Lily ', hobbies:[' Music ', ' Sport ']}
One problem with this code is that when a self reference exists in the object being copied, the program falls into an infinite loop
var a={name: ' Lily '};
A.obj=a;
Deepcopy (a);
When the Chome console runs, the following prompts
Rangeerror:maximum Call stack size exceeded
In order to solve the problem of self reference, add the judgment logic to copy
Function deepcopy (source,target) { var target=target| |
{}; for (var i in source) { //prevent self-referencing if (source[i] === source )
continue; if (typeof source[i] === ' object ') { target[i] = (source[i].constructor
=== array ) ? [] : {} ;
deepcopy (Source[i],target[i]); }else{
target[i]=source[i]; } return target;
} var a={name: ' Lily '};
A.obj=a; Var b=deepcopy (a);//b={name: ' Lily '}
Three, jquery copy implementation
Online There are many analysis of the jquery extend methods, there are not understand can go to search read
Paste an analysis of the source code
Jquery.extend = jquery.fn.extend = function () { var src, copyisarray, copy, name, options, clone, target = arguments[0] | | {}, i = 1, length = arguments.length, deep =
false; // handle a deep copy situation if ( typeof target === "boolean" ) {
deep = target; target = arguments[1] | |
{}; // skip the boolean and the Target        &Nbsp;i = 2; } // handle case when target is a string or something (possible in deep copy) if ( typeof target !== "Object" && !jquery.isfunction (target) ) { target = {}; } // extend jquery itself if only one argument is passed if ( length === i ) {
target = this;
--i; &NBSP;&NBSP;&NBSP;&NBSP} for ( ; i < length; i++ ) { // only deal with non-null/ UndefiNed values if (options = arguments[ &NBSP;I&NBSP] != null ) { // extend the base object for ( name in options ) {
src = target[ name ]; copy =
options[ name ]; // Prevent never-ending loop if ( target === copy ) {&NBSP;&NBSP;&NBSP;&NBSP;&NBsp; continue; } // recurse if we ' Re merging plain objects or arrays if ( deep && copy & & ( jquery.isplainobject (copy) | | (Copyisarray = jquery.isarray (copy) ) ) { if ( copyisarray ) { copyisarray = falsE clone = src && jquery.isarray (SRC) ?
src : []; } else { clone = src &&
Jquery.isplainobject (SRC) ? src : {}; } // never move original objects, clone them target[ name ] =
Jquery.extend ( deep, clone, copy ); // don ' t bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy; }
} } &NBSP;&NBSP;&NBSP;&NBSP} // return the modified object return&nbsP;target; };
Iv. jquery Implementation Questions
When reading the jquery code above, there is a place for questions, and the query code is as follows
Prevent never-ending Loop
if (target = = copy) {
continue;
}
The
notes that in the Extend method, to prevent an infinite loop, there is a logic for this copy operation to be transferred when the target object equals the Copy object. Where the Copy object is the Property object of the Options object.
The question is, why do you want to compare the target object with the Copy object? Shouldn't you be comparing the Copy object and the options object?
With this in doubt, execute
var a={name in a page console that has been introduced into the jquery library: ' Lily '};
A.obj=a;
var b={};
$.extend (true,b,a);
Rangeerror:maximum Call stack size exceeded
You can see that the Extend method does not prevent an infinite loop when there is a self referencing property in a object
then judge target = = = What role does copy play?
var a={name: ' Lily '};
var b={age:19};
A.obj=b;
$.extend (true,b,a);
//At this time b={age:19, name: "Lily"}
Remove the judge = = Copy will fall into an infinite loop? It's not actually.
var a={name: ' Lili '};
var b={age:19};
A.obj=b;
Deepcopy (true,b,a);
//b=object {age:19, Name: "Lili", Obj:object}
//(where Object is b
here deepcopy is the Extend method of jquery that I remove from the above judgment logic, You have implemented a copy of the
Function deepcopy () { var src, copyisarray, copy, name, options, clone, target = arguments[0] | | {}, i = 1, length = arguments.length, deep =
false; // handle a deep copy situation if ( typeof target === "boolean" ) {
deep = target; target = arguments[1] | |
{}; // skip the boolean and the
Target i = 2; &nBSP;} // handle case when target is a string or something (possible in deep copy) if ( typeof target !== "Object" && !jquery.isfunction (target) ) {
target = {}; } // extend jquery itself if only one argument is passed if ( length === i ) { target = this;
--i; &NBSP;&NBSP;&NBSP;&NBSP} for ( ; i < length; i++ ) { // only deal with non-null/ Undefined values if ( (options = arguments[ i ]) != null ) { // Extend the Base object for ( name in options ) {
src = target[ name ]; copy =
options[ name ]; /** // Prevent Never-ending loop if ( options === copy ) {
continue; } */ // recurse if we ' re merging plain objects or arrays if ( deep && copy && ( isplainobject (copy) | | (Copyisarray =isarray (copy) ) ) { if ( copyIsArray ) {
copyisarray = false; clone = src && isarray (SRC) ? src
: []; } else { clone = src &&
Isplainobject (SRC) ? src : {}; } // Never Move original objects, clone them target[ name ] =deepcopy (
deep, clone, copy ); // don ' t bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy; } } }
// return the modified object return target;
}; Var isstring=function (obj) { return object.prototype.tostring.call (obj) =
== ' [object string] ';
}; Var isarray=function (obj) { return object.prototype.tostring.call (obj) ==
= ' [Object array] ';
}; Var isplainobject=function (obj) { return object.prototype.tostring.call (obj)
=== ' [Object object] ';
} var a={name: ' Lili '};
var b={age:19};
A.obj=b; Deepcopy (True,b,a);