Home  >  Article  >  Web Front-end  >  Detailed explanation of jquery's overall architecture analysis and implementation examples_jquery

Detailed explanation of jquery's overall architecture analysis and implementation examples_jquery

WBOY
WBOYOriginal
2016-05-16 16:31:571274browse

The overall jQuery framework is very complicated and not easy to understand. I have been studying this heavy and powerful framework in the past few days. The overall architecture of jQuery can be divided into: entry module, underlying module and functional module. Here, we take jquery-1.7.1 as an example for analysis.

The overall architecture of jquery

Copy code The code is as follows:

16 (function( window, undefined ) {
                    // Construct jQuery object
22 var jQuery = (function() {
25 var jQuery = function(selector, context) {
27                     return new jQuery.fn.init( selector, context, rootjQuery);
28 },
// A bunch of local variable declarations
97 jQuery.fn = jQuery.prototype = {
98          constructor: jQuery,
99 init: function(selector, context, rootjQuery) { ... },
// A bunch of prototype properties and methods
319 };
322          jQuery.fn.init.prototype = jQuery.fn;
324        jQuery.extend = jQuery.fn.extend = function() { ... };
388 jQuery.extend({
// A bunch of static properties and methods
892 });
955        return jQuery;
957 })();
//Omit the code of other modules...
9246  window.jQuery = window.$ = jQuery;
9266 })( window );

Analyzing the above code, we found that jquery adopts the writing method of anonymous function self-execution. The advantage of this is that it can effectively prevent the problem of namespace and variable pollution. Abbreviating the above code is:

Copy code The code is as follows:

(function(window, undefined) {
var jQuery = function() {}
// ...
​ window.jQuery = window.$ = jQuery;
})(window);

Parameter window

The anonymous function passes in two parameters, one is window and the other is undefined. We know that variables in js have scope chains. The two variables passed in will become local variables of the anonymous function, and they will be accessed faster. By passing in the window object, the window object can be used as a local variable. Then, the parameters of the function also become local variables. When accessing the window object in jquery, there is no need to return the scope chain to the top-level scope, thus The window object can be accessed faster.

Parameter undefined

When js searches for a variable, the js engine will first search for the variable in the scope of the function itself. If it does not exist, it will continue to search upwards. If it is found, it will return the variable. If it cannot find it, it will return undefined. undefined is a property of the window object. By passing in the undefined parameter without assigning a value, the scope chain when searching for undefined can be shortened. Within the scope of a self-calling anonymous function, ensure that undefined is truly undefined. Because undefined can be overwritten and given a new value.

What is jquery.fn?

Copy code The code is as follows:

jQuery.fn = jQuery.prototype = {
               constructor: jQuery,
                init: function(selector, context, rootjQuery) { ... },
// A bunch of prototype properties and methods
        };

By analyzing the above code, we found that jQuery.fn is jQuery.prototype. The advantage of writing it this way is that it is shorter. Later, we saw that jquery simply used a $ symbol instead of jquery for simplicity. Therefore, when we use the jquery framework, we often use $(),

Constructor jQuery()

Image description

jQuery objects are not created through new jQuery, but through new jQuery.fn.init:

Copy code The code is as follows:

var jQuery = function(selector, context) {

return new jQuery.fn.init( selector, context, rootjQuery );

}

A variable jQuery is defined here, and its value is the jQuery constructor, which is returned and assigned to the jQuery variable at line 955 (the top code)

jQuery.fn.init

jQuery.fn (line 97 above) is the prototype object of the constructor function jQuery(), and jQuery.fn.init() is the jQuery prototype method, which can also be called a constructor. Responsible for parsing the types of parameters selector and context and performing corresponding searches.

Parameter context: You can not pass it in, or you can pass it in a jQuery object, DOM element, or one of the ordinary js objects
Parameter rootjQuery: jQuery object containing the document object, used for situations such as document.getElementById() failure.

Copy code The code is as follows:

jQuery.fn.init.prototype = jQuery.fn = jQuery.prototype
jQuery(selector [,context])

By default, the search for matching elements starts from the root element document object, that is, the search scope is the entire document tree, but you can also pass in the second parameter context to limit its search scope. For example:

Copy code The code is as follows:

$('div.foo').click(function () {
                 $('span',this).addClass('bar');//Limit the search range, that is, the above context
});
jQuery.extend() and jQuery.fn.extend()

The methods jQuery.extend(object) and jQuery.fn.extend(object) are used to merge two or more objects into the first object. The relevant source code is as follows (part):

Copy code The code is as follows:

jQuery.extend = jQuery.fn.extend = function() {
var options, name, src, copy, copyIsArray, clone,//a set of local variables defined
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false;

jQuery.extend(object); Add a class method to the jQuery class, which can be understood as adding a static method. Such as:

Copy code The code is as follows:

$.extend({
​add:function(a,b){returna b;}
});

Add a "static method" called add for jQuery, and then you can use this method where jQuery is introduced,

$.add(3,4); //return 7
jQuery.fn.extend(object), check out a code demonstration on the official website as follows:

Copy code The code is as follows:


<script><br> jQuery.fn.extend({<br>            check: function() {<br>                return this.each(function() {<br> This.checked = true;<br>             });<br> },<br> ​​​​ uncheck: function() {<br>                return this.each(function() {<br> This.checked = false;<br>             });<br> }<br> });<br> // Use the newly created .check() method<br> $( "input[type='checkbox']" ).check();<br> </script>

CSS selector engine Sizzle

It can be said that jQuery was born to operate DOM. The reason why jQuery is so powerful is due to the CSS selector engine Sizzle. The parsing rules quote an example from the Internet:

selector:"div > p div.aaron input[type="checkbox"]"

Parsing rules:
1 Follow from right to left
2 Take out the last token, such as [type="checkbox"]
                                                                                         matches: Array[3]
type : "ATTR"
                                                                             Checkbox "]"
                                                                                                   } 3 Filter type If type is > ~ empty, one of the four relationship selectors, then skip and continue filtering
4 until it matches one of ID, CLASS, and TAG, because in this way it can be obtained through the browser interface
5 At this time, the seed collection has value, which reduces the conditions for brush selection
6. If there are multiple matching seed collections, further filtering is required. Modify the selector selector: "div > p div.aaron [type="checkbox"]"
7 OK, jump to the next stage of the compilation function



deferred object

In the process of developing websites, we often encounter certain JavaScript operations that take a long time. Among them, there are both asynchronous operations (such as ajax reading server data) and synchronous operations (such as traversing a large array), and the results are not available immediately.

The usual approach is to specify callback functions for them. That is, specify in advance which functions should be called once they have finished running.

However, jQuery is very weak when it comes to callback functions. In order to change this, the jQuery development team designed the deferred object.

To put it simply, the deferred object is jQuery’s callback function solution. In English, defer means "delay", so the meaning of a deferred object is to "delay" execution until a certain point in the future.

Review the traditional way of writing jQuery’s ajax operation:

Copy code The code is as follows: $.ajax({
url: "test.html",
Success: function(){
alert("Haha, successful!");
  },
error:function(){
alert("Something went wrong!");
  }
});


In the above code, $.ajax() accepts an object parameter. This object contains two methods: the success method specifies the callback function after the operation is successful, and the error method specifies the callback function after the operation fails.

After the $.ajax() operation is completed, if you are using a version of jQuery lower than 1.5.0, the XHR object will be returned and you cannot perform chain operations; if the version is higher than 1.5.0, the returned Deferred objects can be chained.

Now, the new way of writing is this:

Copy code The code is as follows:

$.ajax("test.html")
​.done(function(){ alert("Haha, successful!"); })
​.fail(function(){ alert("Error!"); });

Specify callback functions for multiple operations

Another great benefit of the deferred object is that it allows you to specify a callback function for multiple events, which is not possible with traditional writing.

Please look at the following code, which uses a new method $.when():

Copy code The code is as follows:

$.when($.ajax("test1.html"), $.ajax("test2.html"))

 .done(function(){ alert("Haha, successful!"); })

.fail(function(){ alert("Error!"); });

The meaning of this code is to first perform two operations $.ajax("test1.html") and $.ajax("test2.html"). If both are successful, run the callback specified by done() function; if one fails or both fail, the callback function specified by fail() is executed.

Implementation principle of jQuery.Deferred(func)

Three callback function lists are maintained internally: success callback function list, failure callback function list, and message callback function list. Other methods operate and detect around these three lists.

Source code structure of jQuery.Deferred( func ):

Copy code The code is as follows:

jQuery.extend({

Deferred: function( func ) {
// Success callback function list
          var doneList = jQuery.Callbacks( "once memory" ),
// List of failure callback functions
              failList = jQuery.Callbacks( "once memory" ),
// Message callback function list
           progressList = jQuery.Callbacks( "memory" ),
// Initial state
             state = "pending",
                       // Read-only copy of the asynchronous queue
               promise = {
// done, fail, progress
                                  // state, isResolved, isRejected
                              // then, always
                          // pipe
                          // promise                                                               },
                                          // Asynchronous queue               deferred = promise.promise({}),
             key;
​​​​ // Add methods to trigger success, failure, and message callback lists
for (key in lists) {
              deferred[key] = lists[key].fire;
             deferred[ key "With" ] = lists[ key ].fireWith;
}
                // Add a callback function to set the status
deferred.done( function() {
             state = "resolved";
}, failList.disable, progressList.lock )
         .fail( function() {
             state = "rejected";
            }, doneList.disable, progressList.lock );
                 // If the function parameter func is passed in, it will be executed.
           if ( func ) {
                func.call(deferred, deferred);
}

// Return asynchronous queue deferred

         return deferred;

},
}


jQuery.when( deferreds )

Provides the ability to execute callback functions based on the state of one or more objects, typically based on an asynchronous queue with asynchronous events.


Usage of jQuery.when( deferreds )

If multiple asynchronous queue objects are passed in, the method jQuery.when() returns a new read-only copy of the main asynchronous queue object. The read-only copy will track the final status of the passed asynchronous queue.

Once all asynchronous queues become successful, the success callback function of the "main" asynchronous queue is called;

If one of the asynchronous queues becomes failed, the failure callback function of the main asynchronous queue is called.

Copy code The code is as follows:

/*
Request '/when.do?method=when1' returns {"when":1}
Request '/when.do?method=when2' returns {"when":2}
Request '/when.do?method=when3' returns {"when":3}
*/
var whenDone = function(){ console.log( 'done', arguments ); },
WhenFail = function(){ console.log( 'fail', arguments ); };
$.when(
$.ajax( '/when.do?method=when1', { dataType: "json" } ),
$.ajax( '/when.do?method=when2', { dataType: "json" } ),
$.ajax( '/when.do?method=when3', { dataType: "json" } )
).done( whenDone ).fail( whenFail );

Image description

Asynchronous Queue Deferred

Decoupling asynchronous tasks and callback functions

Provide basic functions for ajax module, queue module and ready event.

Prototype properties and methods

Prototype properties and methods source code:

Copy code The code is as follows:

97 jQuery.fn = jQuery.prototype = {
98 constructor: jQuery,
99 init: function(selector, context, rootjQuery) {}
210 selector: "",
213 jquery: "1.7.1",
216 length: 0,
219 size: function() {},
223 toArray: function() {},
229 get: function( num ) {},
241 pushStack: function(elems, name, selector) {},
270 each: function( callback, args ) {},
274 ready: function( fn ) {}, //
284 eq: function( i ) {},
291 first: function() {},
295 last: function() {},
299 slice: function() {},
304 map: function( callback ) {},
310 end: function() {},
316 push: push,
317 sort: [].sort,
318 splice: [].splice
319 };

The selector attribute is used to record the selector expression when jQuery finds and filters DOM elements.
The attribute .length represents the number of elements in the current jquery object.
The method .size() returns the number of elements in the current jquery object. It is functionally equivalent to the attribute length, but length should be used first because it has no function call overhead.

.size() source code is as follows:

Copy code The code is as follows:

size():function(){
Return this.length;
}

Method .toArray() converts the current jQuery object into a real array. The converted array contains all elements. The source code is as follows:

Copy code The code is as follows:

toArray: function() {
          return slice.call( this );
},

Method.get(index) returns the element at the specified position in the current jQuery object, or an array containing all elements. Its source
The code is as follows:

Copy code The code is as follows:

Get: function(num) {
         return num == null ?

                     // Return a 'clean' array
This.toArray():

// Return just the object
( num < 0 ? this[ this.length num ] : this[ num ] );
},


If no parameters are passed in, calling .toArray() returns an array containing the locked elements; if the parameter index is specified, a single element is returned. The index starts counting from 0 and supports negative numbers.

First, it will be judged whether num is less than 0. If it is less than 0, the subscript will be recalculated using length num, and then the array access operator ([]) will be used to obtain the element at the specified position. This is a small method that supports negative subscripts. Tip; if it is greater than or equal to 0, directly return the element at the specified position.

Detailed explanation of the use of eg() and get(): Summary of common jquery methods and usage examples

Method .each() is used to iterate through the current jQuery object and execute the callback function on each element. Method.each() is implemented internally by simply calling the static method jQuery.each():

Copy code The code is as follows:

each: function( callback, args ) {
          return jQuery.each( this, callback, args );
},

The callback function is triggered in the context where the current element is the context, that is, the keyword this always points to the current element, and return false in the callback function can terminate the traversal.

Method .map() iterates through the current jQuery object, executes the callback function on each element, and puts the return value of the callback function into a new jQuery object. This method is often used to get or set the value of a collection of DOM elements.

Copy code The code is as follows:

map: function( callback ) {
          return this.pushStack( jQuery.map(this, function( elem, i ) {
                return callback.call(elem, i, elem);
         }));
},

The prototype method .pushStack() creates a new empty jQuery object, then puts the collection of DOM elements into this jQuery object, and retains a reference to the current jQuery object.

The prototype method.pushStack() is one of the core methods, which provides support for the following methods:

jQuery object traversal: .eq(), .first(), .last(), .slice(), .map().

DOM search and filtering: .find(), .not(), .filter(), .closest(), .add(), .andSelf().

DOM traversal: .parent(), .parents(), .parentsUntil(), .next(), .prev(), .nextAll(), .prevAll(), .nextUnit(), .prevUnit() , .siblings(), .children(), .contents().

DOM insertion: jQuery.before(), jQuery.after(), jQuery.replaceWith(), .append(), .prepent(), .before(), .after(), .replaceWith().
Define method .push(elems, name, selector), which accepts 3 parameters:

Parameter elems: Array of elements (or array-like object) that will be put into the new jQuery object.

Parameter name: The name of the jQuery method that generates the element array elems.

Parameter selector: The parameter passed to the jQuery method, used to modify the prototype attribute.selector.
Method .end() ends the most recent filtering operation in the current chain and restores the matching elements to their previous state

Copy code The code is as follows:

end: function() {
         return this.prevObject || this.constructor(null);
},

Returns the previous jQuery object. If the attribute prevObect does not exist, an empty jQuery object is constructed and returned. The method .pushStack() is used to push into the stack, and the method .end() is used to pop out of the stack

Static properties and methods

The relevant source code is as follows:

Copy code The code is as follows:

388 jQuery.extend({
 389     noConflict: function( deep ) {},
 402     isReady: false,
 406     readyWait: 1,
 409     holdReady: function( hold ) {},
 418     ready: function( wait ) {},
 444     bindReady: function() {},
 492     isFunction: function( obj ) {},
 496     isArray: Array.isArray || function( obj ) {},
 501     isWindow: function( obj ) {},
 505     isNumeric: function( obj ) {},
 509     type: function( obj ) {},
 515     isPlainObject: function( obj ) {},
 544     isEmptyObject: function( obj ) {},
 551     error: function( msg ) {},
 555     parseJSON: function( data ) {},
 581     parseXML: function( data ) {},
 601     noop: function() {},
 606     globalEval: function( data ) {},
 619     camelCase: function( string ) {},
 623     nodeName: function( elem, name ) {},
 628     each: function( object, callback, args ) {},
 669     trim: trim ? function( text ) {} : function( text ) {},
 684     makeArray: function( array, results ) {},
 702     inArray: function( elem, array, i ) {},
 724     merge: function( first, second ) {},
 744     grep: function( elems, callback, inv ) {},
 761     map: function( elems, callback, arg ) {},
 794     guid: 1,
 798     proxy: function( fn, context ) {},
 825     access: function( elems, key, value, exec, fn, pass ) {},
 852     now: function() {},
 858     uaMatch: function( ua ) {},
 870     sub: function() {},
 891     browser: {}
 892 });
 

未完待续、、、今天就先到这里了,下次补齐。别急哈小伙伴们

Statement:
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