Home > Web Front-end > JS Tutorial > Detailed explanation of extend() and fn.extend() methods in jQuery_jquery

Detailed explanation of extend() and fn.extend() methods in jQuery_jquery

WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWB
Release: 2016-05-16 15:56:48
Original
1159 people have browsed it

These two methods use the same code. One is used to merge properties and methods for jQuery objects or ordinary objects. The other is for instances of jQuery objects. Here are a few examples of basic usage:

The html code is as follows:

Copy code The code is as follows:





                                                                                                                                                                                                                                                                                                          





Write the usage in js below:

Merge two ordinary objects

Copy code The code is as follows:
//Merging attributes for two ordinary 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 properties or methods to jQuery objects

Copy code The code is as follows:
$.extend({hehe:function(){alert('hehe');}});
$.hehe(); //alert('hehe')

This usage is very important. It is the implementation method of adding instance properties and methods as well as prototype properties and methods inside jQuery. It is also the method of writing jQuery plug-ins. The following is the use of the extend method in jQuery 1.7.1 to extend its own methods and properties

Copy code The 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 passed in, so by default, this is regarded as the object to be merged and modified

Add properties or methods to jQuery object instances

Copy code The code is as follows:
//Extended merging 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…]

Only merge and do not modify the objects to be merged

Copy code The 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. If you just want to get a merged object but do not want to destroy any of the original objects, you can use this method

Copy code The 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}

If used, recursive merging or deep copy

Copy code The 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"}

For detailed usage, please see the reference manual http://www.w3cschool.cc/manual/jquery/

Let’s analyze how it is implemented in the 1.7.1 source code:

Copy code The 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 is defined. Since the number of parameters is uncertain, the arguments object is directly called to access the passed parameters

Variable options: points to a source object.
Variable name: represents an attribute name of a source object.
Variable src: Represents the original value of an attribute of the target object.
Variable copy: represents the value of an attribute of a source object.
Variable copyIsArray: Indicates whether the variable copy is an array.
Variable clone: ​​represents the correction value of the original value during deep copying.
Variable target: points to the target object.
Variable i: represents the starting index of the source object.
Variable length: indicates the number of parameters and is used to modify the variable target.
Variable deep: indicates whether to perform deep copy, the default is false.

In order to better understand the code implementation, here is an example given above as a demonstration to observe the execution of the source code

Copy code The 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 code The 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 it is a deep copy. If the first parameter is a Boolean value, then give the value of the first parameter to deep, and then use the second parameter as the target object. If the second parameter does not exist, assign it to one. Empty object, change the subscript of the source object to 2. In this example, it is done here because the first parameter is true and then deep is changed to true. The target is modified to the second parameter, which is obj1. The starting subscript of the source object is 2, which means starting from the third one as the source object, which is obj2

in this example.

Copy code The 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 = {};
}

The target is further processed here. Adding custom attributes is invalid for non-object and function data types. For example, strings can call their own methods and attributes

Copy code The 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 means that there is no target object. Under normal circumstances, length should be greater than the value of i. Then use this as the target object at this time and reduce the i value by one to achieve the length value greater than the i value. (1 greater than i)

This is the implementation principle of jQuery’s method of extending attributes to itself, as long as the target object is not passed in

Two possible situations: $.extend(obj) or $.extend(false/true,obj);

Copy code The 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;
                }
            }
        }
    }

这个部分就是此方法的核心了,从arguements对象的第i个下标值开始循环操作首先过滤掉源对象是null或者是undefined的情况可以看到其实

源对象不一定真的就是对像,也可以是其他类型的值比如字符串比如这样写:

复制代码 代码如下:

console.log($.extend({'name':'tom'},'aa'));   //Object {0: "a", 1: "a", name: "tom"}

是不是感觉很奇怪啊?究竟是怎么实现的呢?下面接着看

过滤完之后开始进行for循环 src保存的是目标对象的某个键的值,copy属性保存的源对象的某个键的值,这两个键都是一样的

复制代码 代码如下:

// Prevent never-ending loop
If ( target === copy ) {
                         continue;
                }

If a certain attribute value of the source object is the target object, it may cause an infinite loop and cause the program to crash, so a restriction is made here to allow it to skip this loop. For example:

Copy code The code is as follows:

var o = {};
o.n1 = o;
$.extend( true, o, { n2: o } );
// throw exception:
// Uncaught RangeError: Maximum call stack size exceeded

But doing so will also unfairly affect some normal situations such as:

Copy code The code is as follows:

var obj1={a:'a'}
var obj2={a:obj1};
console.log($.extend(obj1,obj2)); //Object {a: "a"}

This situation also satisfies that the source object value is equal to the target object, but it turns out that the attribute value of a of obj1 has not been modified, because continue is executed. Below, comment out this paragraph in the source code before executing

Copy code The code is as follows:

Object {a: Object}

At this time, it has been modified normally. I personally feel that this area needs improvement;

Then there is an if judgment, which is to distinguish whether it is a deep copy. First, do not look at the deep copy and first look at the general

Copy code The code is as follows:

target[ name ] = copy;

It is very simple. As long as the copy has a value, it is copied directly to the target object. If the target object has some modifications, it is added. In this way, the merge is achieved.

After the for loop, the new target object is returned, so the target object is finally modified, and the result is the same as the returned result.

Copy code The code is as follows:

// Return the modified object
Return target;
};

Let’s talk about how to handle deep copy

First ensure that deep is true, copy has a value and is an object or array (if it is not an object or array, deep copying is out of the question) and then it is processed by arrays and objects. Let’s look at the array first:

Copy code The code is as follows:

if ( copyIsArray ) {
          copyIsArray = false;
​ ​ ​ clone = src && jQuery.isArray(src) ? src : [];

} else {
​​​​clone = src && jQuery.isPlainObject(src) ? src: {};
}

If the value of the array copyIsArray is true, then go inside and change the value to false. For the source object attribute of the current loop, the target object may or may not have it. If it does, judge whether it is an array. If so, it is the original one. If the array is unchanged, let it become an array, because since the current attribute of the source object is the array, the last target element must also be an array. Either an array or an object. Change the current properties of the target object to an object.

Copy code The code is as follows:

// Never move original objects, clone them
Target[ name ] = jQuery.extend( deep, clone, copy );

Then recursively merge the current attribute value of the source object (which is an array or object) and the current attribute of the modified target object and assign the returned new array or object to the target object, ultimately achieving deep copying.

But there is a rather strange phenomenon here, such as this:

Copy code The code is as follows:

console.log($.extend({a:1},'aa')); //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. It turns out that the for...in loop operates on strings

Copy code The code is as follows:

var str='aa';
for(var name in str){
console.log(name);
console.log(str[name])
}

This is also possible, it will split the string and read it according to the numerical subscript, but in the source code

Copy code The code is as follows:

if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) )

is limited to arrays and objects, so will it have no effect during deep copying?

After my test, deep copying is also possible, because the copied value in the source code turned into an anonymous function

alert(jQuery.isPlainObject(copy)); //true

As for why it is a function, I haven’t figured it out yet and will leave it to be solved later!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Issues
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template