For details about the extend () and fn. extend () methods in jQuery, jqueryfn. extend
The two methods use the same code. One is used to merge attributes and methods for jQuery objects or common objects. The other is an example of jQuery objects. for basic usage, the following are examples:
The html code is as follows:
Copy codeThe Code is as follows:
<! Doctype html>
<Html>
<Head>
<Title> </title>
<Script src = 'jquery-1.7.1.js'> </script>
</Head>
<Body>
</Body>
</Html>
The usage in js is as follows:
Merge two common objects
Copy codeThe Code is as follows:
// Merge attributes for two common objects
Var obj1 = {name: 'Tom ', age: 22 };
Var obj2 = {name: 'jack', height: 180 };
Console. log ($. extend (obj1, obj2); // Object {name: "Jack", age: 22, height: 180}
Add attributes or methods to jQuery objects
Copy codeThe Code is as follows:
$. Extend ({hehe: function () {alert ('hei ');}});
$. Hehe (); // alert ('hei ')
This usage is very important. It is also the method for compiling jQuery plug-ins to add instance attributes and METHODS Inside jQuery, as well as the implementation of prototype attributes and methods, the following describes how to use the extend method to extend the attributes of jQuery1.7.1.
Copy codeThe Code is as follows:
JQuery. extend ({
NoConflict: function (deep ){
If (window. $ === jQuery ){
Window. $ =_$;
}
If (deep & window. jQuery === jQuery ){
Window. jQuery = _ jQuery;
}
Return jQuery;
},
// Is the DOM ready to be used? Set to true once it occurs.
IsReady: false,
// A counter to track how many items to wait for before
// The ready event fires. See #6781
ReadyWait: 1,
.....
In this example, only one object parameter is input, so this is used as the object to be merged and modified by default.
Add attributes or methods to jQuery object instances
Copy codeThe Code is as follows:
// Extension merge for jQuery instances
Console. log ($ ('img '). extend ({'title': 'img '}); // [img, img # img. img, prevObject: jQuery. fn. jQuery. init [1], context: document, selector: "img", title: "img", constructor: function…]
Merge only without modifying the objects to be merged
Copy codeThe Code is as follows:
Var obj1 = {name: 'Tom ', age: 22 };
Var obj2 = {name: 'jack', height: 180 };
Console. log ($. extend (obj1, obj2); // Object {name: "Jack", age: 22, height: 180}
Console. log (obj1); // Object {name: "Jack", age: 22, height: 180}
By default, the object to be merged is modified like the returned result. You can use this method if you only want to get a merged object and do not want to destroy any original object.
Copy codeThe Code is as follows:
Var obj1 = {name: 'Tom ', age: 22 };
Var obj2 = {name: 'jack', height: 180 };
Var empty = {};
Console. log ($. extend (empty, obj1, obj2); // Object {name: "Jack", age: 22, height: 180}
Console. log (obj1); // Object {name: "Tom", age: 22}
Recursive merge or deep copy
Copy codeThe Code is as follows:
Var obj1 = {name: 'Tom ', love: {drink: 'milk', eat: 'bread '}};
Var obj2 = {name: 'jack', love: {drink: 'water', sport: 'football '}};
Console. log ($. extend (false, obj1, obj2). love); // Object {drink: "water", sport: "football "}
Console. log ($. extend (true, obj1, obj2 )). love); // Object {drink: "water", eat: "bread", sport: "football "}
Detailed usage can see reference manual http://www.w3cschool.cc/manual/jquery/
The following describes how to implement the 1.7.1 source code:
Copy codeThe Code is as follows:
JQuery. extend = jQuery. fn. extend = function (){
Var options, name, src, copy, copyIsArray, clone,
Target = arguments [0] | | {},
I = 1,
Length = arguments. length,
Deep = false;
...
}
First, a set of variables are defined. because the number of parameters is unknown, the parameters passed by the arguments object are directly called.
Variable options: points to a source object.
‰ Variable name: indicates an attribute name of a source object.
Src: the original value of an attribute of the target object.
Copy: indicates the value of an attribute of a source object.
CopyIsArray: indicates whether the variable copy is an array.
Clone: the modified value of the original value during deep replication.
Target: the target object.
‰ Variable I: indicates the starting subscript of the source object.
‰ Variable length: indicates the number of parameters, used to modify the variable target.
‰ Variable deep: Indicates whether to perform deep replication. The default value is false.
To better understand the code implementation, the example above is used as an example to demonstrate how the source code is executed.
Copy codeThe Code is as follows:
Var obj1 = {name: 'Tom ', love: {drink: 'milk', eat: 'bread '}};
Var obj2 = {name: 'jack', love: {drink: 'water', sport: 'football '}};
$. Extend (true, obj1, obj2)
Source code analysis
Copy codeThe Code is as follows:
// Handle a deep copy situation
If (typeof target = "boolean "){
Deep = target;
Target = arguments [1] || {};
// Skip the boolean and the target
I = 2;
}
Determine whether deep replication is performed. If the first parameter is a Boolean value, the value of the first parameter is given to deep, and the second parameter is used as the target object, if the second parameter does not exist, assign a value to an empty object and change the subscript of the source object to 2, in this example, It is here because the first parameter is true and then deep is changed to true, and target is corrected to the second parameter, that is, obj1, the starting subscript of the source object is 2, which means that the source object is the obj2 object in this example.
Copy codeThe Code is as follows:
// Handle case when target is a string or something (possible in deep copy)
If (typeof target! = "Object "&&! JQuery. isFunction (target )){
Target = {};
}
Here, the target is further processed. For non-object and function data types, adding custom attributes is invalid. For example, the built-in methods and attributes can be called by the string itself.
Copy codeThe Code is as follows:
// Extend jQuery itself if only one argument is passed
If (length = I ){
Target = this;
-- I;
}
If the length attribute is equal to the value of I, it indicates that no target object exists. Normally, the length must be greater than the value of I, in this case, this is used as the target object to reduce the I value by one and realize that the length value is greater than the I value (1 larger than I)
This is the implementation principle of jQuery's method for extending attributes for itself, as long as it does not pass in the target object.
There are two possible cases: $. extend (obj) or $. extend (false/true, obj );
Copy codeThe Code is as follows:
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 (target = copy ){
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;
}
}
}
}
This part is the core of this method. Starting from the I lower mark of The arguements object, the circular operation first filters out whether the source object is null or undefined.
The source object may not necessarily be an object or another type of value, such as a string, for example:
Copy codeThe Code is as follows:
Console. log ($. extend ({'name': 'Tom '}, 'A'); // Object {0: "a", 1: "a", name: "tom "}
Isn't it strange? How is it implemented? Next let's take a look.
After filtering, the for loop src is started to save the value of a key of the target object. The copy attribute stores the value of a key of the source object, both of which are the same.
Copy codeThe Code is as follows:
// Prevent never-ending loop
If (target = copy ){
Continue;
}
If a property value of the source object is the target object, it may cause an endless loop and cause program crash. Therefore, we have made a restriction to skip this loop. For example:
Copy codeThe Code is as follows:
Var o = {};
O. n1 = o;
$. Extend (true, o, {n2: o });
// Throw an exception:
// Uncaught RangeError: Maximum call stack size exceeded
However, some normal cases such:
Copy codeThe Code is as follows:
Var obj1 = {a: 'A '}
Var obj2 = {a: obj1 };
Console. log ($. extend (obj1, obj2); // Object {a: ""}
In this case, the value of the source object is equal to the value of the target object, but the result shows that the attribute value of a of obj1 is not modified because the continue is executed. The following comments of the source code are commented out in the execution.
Copy codeThe Code is as follows:
Object {a: Object}
At this time, it is changed normally. I personally feel that this place needs to be improved;
Next, an if statement is used to determine whether or not to perform deep replication first.
Copy codeThe Code is as follows:
Target [name] = copy;
It is easy to copy the object directly to the target object as long as the copy object has a value. If some of the target objects are modified, the object will be added. In this way, the merge will be realized.
After a for loop, the new target object is returned, so the target object is modified at the end, and the result is the same as the returned result.
Copy codeThe Code is as follows:
// Return the modified object
Return target;
};
Next, let's talk about how to deal with deep replication.
First, ensure that deep is true, copy has a value and is an object or an array (if it is not an object or an array, it cannot be discussed in depth), and then the score group and object are processed, first, let's look at the array:
Copy codeThe Code is as follows:
If (copyIsArray ){
CopyIsArray = false;
Clone = src & jQuery. isArray (src )? Src: [];
} Else {
Clone = src & jQuery. isPlainObject (src )? Src :{};
}
If the array copyIsArray value is true and then the value is changed to false, the target object may or may not exist for the source object attribute of the current loop, if yes, let's determine whether the array is an array. If the original array remains unchanged, it will be converted into an array. Since the current attribute of the source object is the final target element of the array, it must also be an array. Either an array or an object changes the current attribute of the target object to an object.
Copy codeThe Code is as follows:
// Never move original objects, clone them
Target [name] = jQuery. extend (deep, clone, copy );
Then, the current attribute value (an array or object) of the source object and the current attribute of the transformed target object are recursively merged, and the new array or object returned is assigned to the target object, deep replication is achieved.
However, there is a strange phenomenon, such as the following operations:
Copy codeThe Code is as follows:
Console. log ($. extend ({a: 1}, 'A'); // Object {0: "a", 1: "a", a: 1}
The original source object is not necessarily the Object e, and the string can be split and merged with the target object. The original for... in loop is the operation string.
Copy codeThe Code is as follows:
Var str = 'a ';
For (var name in str ){
Console. log (name );
Console. log (str [name])
}
This is also possible. It will split the string and read it by numerical subscript, but in the source code
Copy codeThe Code is as follows:
If (deep & copy & (jQuery. isPlainObject (copy) | (copyIsArray = jQuery. isArray (copy ))))
There are restrictions on arrays and objects. Is there no effect in deep replication?
After my tests, deep replication is also possible, because the copy value in the source code turns into an anonymous function.
Alert (jQuery. isPlainObject (copy); // true
I have not figured out why the function is to be solved in the future!