Implementation of jQuery. extend ()

Source: Internet
Author: User

Extend () in jQuery ()

Extend () is one of the basic functions of jQuery. It is used to expand existing objects. For example, the following code:
Html code
• <Script type = "text/javascript" src = "jquery-1.5.2.js"> </script>
• <Script>
• Obj1 = {a: 'A', B: 'B '};
• Obj2 = {x: {xxx: 'xxx', yyy: 'yyy'}, y: 'y '};

• $. Extend (true, obj1, obj2 );

• Alert (obj1.x. xxx); // get "xxx"

• Obj2.x. xxx = 'zzz ';
• Alert (obj2.x. xxx); // get "zzz"
• Alert (obj1.x. xxx); // carries "xxx"
• </Script>

$. Extend (true, obj1, obj2) indicates the extended object obj1 in obj2. The first parameter is set to true, which indicates deep replication.
Although obj1 does not have the "x" attribute, after expansion, obj1 not only has the "x" attribute, the modification to the "x" attribute in obj2 does not affect the value of the "x" attribute in obj1. This is the so-called "Deep replication.
Implementation of light Replication

If you only need to implement the shortest copy, you can use a statement similar to the following:
Javascript code
• $ = {
• Extend: function (target, options ){
• For (name in options ){
• Target [name] = options [name];
•}
• Return target;
•}
•};

That is, simply copy the attributes in options to the target. We can still test with similar code, but the results are different (assuming our js name is "jquery-extend.js "):
Html code
• <Script type = "text/javascript" src = "jquery-extend.js"> </script>
• <Script>
• Obj1 = {a: 'A', B: 'B '};
• Obj2 = {x: {xxx: 'xxx', yyy: 'yyy'}, y: 'y '};

• $. Extend (obj1, obj2 );

• Alert (obj1.x. xxx); // get "xxx"

• Obj2.x. xxx = 'zzz ';
• Alert (obj2.x. xxx); // get "zzz"
• Alert (obj1.x. xxx); // "zzz"
• </Script>

Obj1 has the "x" attribute, but this attribute is an object. modifying the "x" attribute in obj2 also affects obj1. this may cause hard-to-find errors.
Implementation of deep Replication

If we want to implement "Deep replication", we should call extend recursively when the Copied object is an array or object. The following code is a simple implementation of "Deep replication:
Javascript code
• $ = {
• Extend: function (deep, target, options ){
• For (name in options ){
• Copy = options [name];
• If (deep & copy instanceof Array ){
• Target [name] = $. extend (deep, [], copy );
•} Else if (deep & copy instanceof Object ){
• Target [name] = $. extend (deep, {}, copy );
•} Else {
• Target [name] = options [name];
•}
•}
• Return target;
•}
•};

There are three situations:
1. When the attribute is an array, the target [name] is initialized as an empty array and extend is recursively called;
2. When the attribute is an object, the target [name] is initialized as an empty object and extend is recursively called;
3. Otherwise, copy the property directly.

The test code is as follows:
Html code
• <Script type = "text/javascript" src = "jquery-extend.js"> </script>
• <Script>
• Obj1 = {a: 'A', B: 'B '};
• Obj2 = {x: {xxx: 'xxx', yyy: 'yyy'}, y: 'y '};
• $. Extend (true, obj1, obj2 );
• Alert (obj1.x. xxx); // get "xxx"
• Obj2.x. xxx = 'zzz ';
• Alert (obj2.x. xxx); // get "zzz"
• Alert (obj1.x. xxx); // get "xxx"
• </Script>

If the parameter is set to deep copy, the modification to obj2 will not affect obj1. however, this code still has some problems, for example, "instanceof Array" may be incompatible with ie5. The implementation in jQuery is actually more complicated.
More complete implementation of www.2cto.com

The following implementation is closer to extend () in jQuery:
Javascript code
• $ = Function (){
• Var copyIsArray,
• ToString = Object. prototype. toString,
• HasOwn = Object. prototype. hasOwnProperty;

• Class2type = {
• '[Object Boolean]': 'boolean ',
• '[Object Number]': 'number ',
• '[Object String]': 'string ',
• '[Object Function]': 'function ',
• '[Object Array]': 'array ',
• '[Object Date]': 'date ',
• '[Object RegExp]': 'regexp ',
• '[Object Object]': 'object'
•},

• Type = function (obj ){
• Return obj = null? String (obj): class2type [toString. call (obj)] | "object ";
•},

• IsWindow = function (obj ){
• Return obj & typeof obj = "object" & "setInterval" in obj;
•},

• IsArray = Array. isArray | function (obj ){
• Return type (obj) = "array ";
•},

• IsPlainObject = function (obj ){
• If (! Obj | type (obj )! = "Object" | obj. nodeType | isWindow (obj )){
• Return false;
•}

• If (obj. constructor &&! HasOwn. call (obj, "constructor ")
•&&! HasOwn. call (obj. constructor. prototype, "isPrototypeOf ")){
• Return false;
•}

• Var key;
• For (key in obj ){
•}

• Return key = undefined | hasOwn. call (obj, key );
•},

• Extend = function (deep, target, options ){
• For (name in options ){
• Src = target [name];
• Copy = options [name];

• If (target = copy) {continue ;}

• If (deep & copy
• & (IsPlainObject (copy) | (copyIsArray = isArray (copy )))){
• If (copyIsArray ){
• CopyIsArray = false;
• Clone = src & isArray (src )? Src: [];

•} Else {
• Clone = src & isPlainObject (src )? Src :{};
•}

• Target [name] = extend (deep, clone, copy );
•} Else if (copy! = Undefined ){
• Target [name] = copy;
•}
•}

• Return target;
•};

• Return {extend: extend };
•}();

First, $ = function () {...} (); can be understood as similar to the following statement:
Java code
• Func = function (){...};
• $ = Func ();
That is, execute the function immediately and assign the result to $. In this way, the function can be used to manage the scope to avoid local variables or local functions affecting the full local area. In addition, we only want the user to call $. extend () and hide the internally implemented functions. Therefore, the final returned object only contains extend:
Java code
• Return {extend: extend };

Next, let's look at the difference between the extend function and the previous one. The first is the additional sentence:
Java code
• If (target = copy) {continue ;}
This is to avoid infinite loops. If the copy attribute to be copied is the same as the target, that is, copying "yourself" as "your own attribute" may lead to an unpredictable loop.

Then, you can determine whether the object is an array:
Java code
• Type = function (obj ){
• Return obj = null? String (obj): class2type [toString. call (obj)] | "object ";
•},
• IsArray = Array. isArray | function (obj ){
• Return type (obj) = "array ";
•}
If the browser has a built-in Array. isArray implementation, use the browser's own implementation method. Otherwise, convert the object to String to see if it is "[object Array]".

Finally, let's look at the implementation of isPlainObject one by one:
Java code
• If (! Obj | type (obj )! = "Object" | obj. nodeType | isWindow (obj )){
• Return false;
•}
If obj. nodeType is defined, it indicates that this is a DOM element. This Code indicates that deep replication is not performed in the following four cases:
1. The object is undefined;
2. If it is converted to String, it is not "[object Object]";
3. obj is a DOM element;
4. obj is a window.
The reason for not performing deep replication on DOM elements and Windows is probably because they contain too many attributes. Especially for window objects, all variables declared in the whole area are their attributes, not to mention the built-in attributes.

Next is the test related to the constructor:
Javascript code
• If (obj. constructor &&! HasOwn. call (obj, "constructor ")
•&&! HasOwn. call (obj. constructor. prototype, "isPrototypeOf ")){
• Return false;
•}
If an object has a constructor but is not its own property, it means that the constructor is inherited by prototye, and in this case, no deep replication is performed. This can be understood by combining the following code:
Javascript code
• Var key;
• For (key in obj ){
•}

• Return key = undefined | hasOwn. call (obj, key );
These codes are used to check whether all attributes of an object are their own, because when traversing an object attribute, the object will first traverse from its own attribute, therefore, you only need to check whether the final attribute is its own.

This indicates that if the object inherits the constructor or attribute through prototype, deep replication is not performed on the object. This may also be due to the complexity of such objects, to avoid introducing uncertain factors or processing a large amount of time for copying a large number of attributes, we can also see from the function name that only "PlainObject" is used for deep replication ".
If we use the following code for testing:
Javascript code
• <Script type = "text/javascript" src = "jquery-1.5.2.js"> </script>
• <Script>
• Function O (){
• This. yyy = 'yyy ';
•}

• Function X (){
• This. xxx = 'xxx ';
•}

• X. prototype = new O ();

• X = new X ();

• Obj1 = {a: 'A', B: 'B '};
• Obj2 = {x: x };
• $. Extend (true, obj1, obj2 );

• Alert (obj1.x. yyy); // get "xxx"
• Obj2.x. yyy = 'zzz ';
• Alert (obj1.x. yyy); // get "zzz"
• </Script>
We can see that this situation does not require deep replication.

In short, the implementation of extend () in jQuery takes into account compatibility with browsers, avoiding low performance and unexpected errors.
 

Source of Water

Related Article

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.