jquery Overall architecture Source code analysis

Source: Internet
Author: User
Tags jquery library

Recently has been studying the JQuery source code, the first look at the source confused no clue, the real calm down to see the writing is really exquisite, let you sigh the beauty of code.

Its clear structure, high cohesion and low coupling, combined with outstanding performance and ease of scalability, the thoughtful and powerful customization capabilities of browser compatibility (functional defects, progressive enhancement), and Ajax are all amazing.

In addition, read the source code let me access to a lot of knowledge at the bottom. A new understanding of native JS, frame design, code optimization, and a series of articles on JQuery parsing will be written next.

I am on GitHub on the full text of the JQuery source code comments, interested can be onlookers. JQuery v1.10.2 source Annotations.

Online has a lot of reading the jQuery source of the article, as the first series of the opening, think before you want to go up a "in the light of jquery" title, seniority is shallow, unable to jquery analysis of the well-written, but jquery source does have a lot of clever design, Readers of all levels can reap the benefits, so they intend to share some of the knowledge they have learned from them. I intend to analyze it from the whole and the branch section. This article focuses on the overall structure of jquery and some preliminary preparations, first of all, look at the overall architecture of jquery:

Overall architecture

Unlike the obscure details of each module of the jquery code, the structure of the jquery framework is very clear and is broadly divided into modules as shown in code.

The first look at JQuery source code may be easy to confused, because the 9000 lines of coding feel no end, so it is important to understand the author's ideas.

Overall, I think that JQuery is a total – sub-structure, although JavaScript has a scope of promotion mechanism, but more than 9,000 lines of code in order to relate to each other, does not mean that all variables are defined at the top of the. In JQuery, only variables, regular expressions that are used globally are defined at the beginning of the code, and each module starts with a definition of variables, regular, methods, and so on that are used only in this module. So at the beginning of the reading process there will be a lot of variables that do not understand its role, regular, method.

So, I think it is very important to read the source code is to abandon the process-oriented way of thinking, do not deliberately pursue from top to bottom every sentence must be understood at the beginning. It is very likely that at first you are stuck in a strange method or variable, and want to know the effect of this method or variable, but it is probably going to be called at thousands of lines. To pursue this word-for-word approach, it is likely that the enthusiasm for reading after a few snags has been greatly affected.

The reason says a lot, then comes down into the real body, to jqurey some preliminary preparation, small details analysis:

Closure Structure
Wrapped up in a function field, is the so-called sandbox//In this case the variable defined by Var, which belongs to the local variable in this function domain, avoids the pollution global//The external variables required by the current sandbox are introduced through the function parameters//As long as the parameters are guaranteed to be consistent with the interface provided internally, You can also arbitrarily replace the passed in Parameters (function (window, undefined) {//JQuery code}) (window);

The specific implementation of JQuery is contained in an immediately executed function closure, in order to not pollute the global scope, only after exposing the 2 variables of $ and jQuery to the outside world, as far as possible to avoid variable collisions. There is another way to use it:

(function (window) {//JS code}) (window, undefined);

The first type of writing that is more admired is the way JQuery is written. What's the difference between the two, when our code runs in an earlier environment (Pre-es5,eg. Internet Explorer 8), undefined is only a variable and its value can be overwritten. This means that you can do the following:

undefined = 42console.log (undefined)//42

When using the first way, you can make sure that the undefined you need is really undefined.

It is also necessary to suggest that jQuery here has a compression-optimized detail, using the first way, when the code is compressed, window and undefined can be compressed to 1 letters and make sure that they are window and undefined.

Compression Policy//W-windwow, U-undefined (function (w, u) {}) (window);
No new construction

Hey, think back to the way you instantiate a jquery object when using jquery:

No new construct $ (' #test '). Text (' test ');//can also use Newvar test = new $ (' #test '); Test.text (' Test ');

Most people use jquery as the first way to construct without new, directly $ ("), which is a convenient place for jquery. When we use the first non-new construct, its essence is the equivalent of new jquery (), how is it implemented within JQuery? Look:

(Function (window, undefined) {    var    //...    jquery = function (selector, context) {        //The jquery object is actually just the Init constructor ' enhanced '//        look at this , the instantiation method of JQuery () actually calls its expanded prototype method JQuery.fn.init        return new JQuery.fn.init (selector, context, rootjquery);    },    //Jquery.prototype is a prototype of jquery, mounted in the method above, you can make all the generated JQuery objects use    Jquery.fn = Jquery.prototype = {        ///instantiation method, which A method can be called the JQuery object constructor        init:function (selector, context, rootjquery) {            //...        }    }    This sentence is very key, also very around    //jquery does not instantiate jquery using the new operator, but instead calls its function directly    //To implement this, then JQuery will be considered a class and return a correct instance    //And the instance will be able to Proper access to properties and methods on the jquery class prototype    //jquery is solved by prototype delivery, and the prototype of jquery is passed on to JQuery.prototype.init.prototype    // So the instance generated by this method is still Jquery.fn, so the properties and methods on the JQuery class prototype can be accessed correctly    JQuery.fn.init.prototype = Jquery.fn;}) (window);

Most people first See JQuery.fn.init.prototype = Jquery.fn This sentence will be card master, very puzzled. But this is really the wonderful thing about JQuery. It is important to understand these sentences and analyze them in a few points:

1) First of all be clear, use $ (' xxx ') This instantiation way, its internal call is return new JQuery.fn.init (selector, context, rootjquery) This sentence, that is, the construction instance is handed The JQuery.fn.init () method is completed.

2) Set the prototype property of the JQuery.fn.init to Jquery.fn, then the prototype object of the object generated with the new JQuery.fn.init () is Jquery.fn, so the function attached to the JQUERY.FN is equivalent to Mounted on a JQuery object generated by JQuery.fn.init (), all objects generated using new JQuery.fn.init () are also able to access all the prototype methods on the Jquery.fn.

3) that is, the instantiation method has such a chain of relationships

    • JQuery.fn.init.prototype = Jquery.fn = Jquery.prototype;
    • New JQuery.fn.init () equals new JQuery ();
    • jquery () returns new JQuery.fn.init (), and var obj = new jquery (), so these 2 are equivalent, so we can instantiate a JQuery object without a new one.
Overloading of methods

Another reason why JQuery source is obscure is that it uses a lot of method overloads, but it is easy to use:

Gets the value of the Title property $ (' #id '). attr (' title ');//Set the value of the Title property $ (' #id '). attr (' title ', ' JQuery ');//Gets the value of a CSS property $ (' #id '). CSS (' Title ');//Set the value of a CSS property $ (' #id '). CSS (' width ', ' 200px ');

Overloading of methods is a way to implement a variety of functions, often get and set, although it is difficult to read, but from a practical point of view, this is why jquery is so popular, most people use the jquery () construction method is the most used to directly instantiate a JQuery object, but in its internal implementation, there are 9 different ways to reload the scene:

Accepts a string that contains a CSS selector for matching element collection jquery ([Selector,[context]])//Incoming single domjquery (element)//Incoming DOM array jquery (Elementarray )//Incoming JS object jquery (object)///Incoming jquery object jquery (jquery object)//The string that is passed into the original HTML to create a DOM element jquery (Html,[ownerdocument]) Jquer Y (Html,[attributes])//input null parameter jquery ()//bind a function that executes after the DOM document is loaded jquery (callback)

So reading the source code, it is very important to read with the jquery API to understand how many of the methods overloaded, and I want to say that the jquery source code some methods of implementation is particularly long and cumbersome, because jquery itself as a very strong framework for versatility, A method is compatible with a number of situations, but also allows the user to pass in a variety of parameters, resulting in internal processing logic is very complex, so when the interpretation of a method to feel the obvious difficulties, trying to jump out of the block of the code itself, standing in the higher dimensions to think of these complex logic is to deal with or compatible with what, Whether it is overloaded, why write this, there will be a different harvest. Second, also because of this reason, JQuery source code There are many compatible with the low version of HACK or logic is very obscure and cumbersome snippets, browser-compatible such a pit is extremely easy for a front-end engineer can not learn the essence of programming, so don't be too obsessed with some scrap, even if compatibility is important, should also moderate study understanding, enough.

JQuery.fn.extend and Jquery.extend

The Extend method is an important method in jquery, and it is used internally by Jquey to extend static or instance methods, and it is used when we develop jquery plug-ins. But internally, there are two extend methods of JQuery.fn.extend and jquery.extend, and distinguishing between the two extend methods is a key part of understanding JQuery. First look at the conclusion:

1) Jquery.extend (object) to extend the JQuery class itself, adding a new static method to the class;

2) JQuery.fn.extend (object) Adds an instance method to the jquery object, that is, the new method added by this extend, the instantiated jquery object can be used, because it is mounted on the Jquery.fn method (mentioned above, Jquery.fn = Jquery.prototype).

Their official explanation is:

1) jquery.extend (): Merge two or more objects into the first one,

2) JQuery.fn.extend (): Mount the object to the prototype property of jquery to extend a new jquery instance method.

In other words, using the Jquery.extend () extended static method, we can call directly using $.xxx (XXX is the extension of the method name),

Using the JQuery.fn.extend () Extended instance method requires a $ (). XXX call.

Source parsing is long, you can also go here to read:

Extended Merge function//merge the properties of two or more objects into the first object, and most of the subsequent functions of jQuery are extended through the function//Although the implementation is the same, but pay attention to the difference between the use of different, then why the two methods point to the same function implementation, but the implementation of various functions,// Read the source to see that this is due to the power of this//if you pass in two or more objects, the properties of all objects are added to the first object target//if only one object is passed in, the object's properties are added to the JQuery object, that is, by adding a static method//In this way, We can add a new method to the jquery namespace that can be used to write jquery plugins//If you do not want to change the incoming object, you can pass in an empty object: $.extend ({}, Object1, object2);//The default merge operation is incessantly generation, even if A property of target is an object or attribute that is also fully overwritten instead of merging//If the first argument is true, then deep copy//The property inherited from the object prototype is copied, the property with value undefined is not copied//For performance reasons, JavaScript Properties with a self-type are not merged jquery.extend = JQuery.fn.extend = function () {var src, copyisarray, copy, name, options, clone, Tar get = Arguments[0] | |    {}, I = 1, length = arguments.length, deep = false;         Handle a deep copy situation//target is the first parameter passed in//if the first argument is a Boolean type, it indicates whether to be deeply recursive, if (typeof target = = = "Boolean") {        Deep = target; target = Arguments[1] | |        {};    Skip the Boolean and the target//if the first parameter of type Boolean is passed, I is starting from 2 i = 2; }//Handle case at Target is A string or something (possible in deep copy)//If the first parameter passed in is a string or other if (typeof target!== "Object" &&!jqu    Ery.isfunction (target)) {target = {};        }//Extend jquery itself if only one argument is passed//if the length of the parameter is 1, it means jquery static method if (length = = = i) {        target = this;    I.;        }//Can pass in multiple replication sources//I is 1 or 2 for (; i < length; i++) {//deal with non-null/undefined values            Copy all properties of each source to target on if (options = arguments[i]! = NULL) {//Extend the Base Object for (name in options) {//SRC is the value of the source (that is, itself)//copy is about to replicate the past value of src = target[n                AME];                copy = Options[name];                Prevent never-ending loop//to prevent loops, such as extend (true, target, {' target ': target});                if (target = = = copy) {continue;     }//Recurse If we ' re merging plain objects or arrays           Here is the recursive call, which will eventually go to the following else if branch//jquery.isplainobject to test whether it is purely object//pure object refers to the pass "{}" or "New Object"//If the deep copy if (Deeper && copy && (jquery.isplainobje CT (copy) | | (Copyisarray = Jquery.isarray (copy))))                        {//array if (Copyisarray) {Copyisarray = false; clone = src && jquery.isarray (src)?                        SRC: [];                    Object} else {clone = src && jquery.isplainobject (src)? src: {};                    }//Never move original objects, clone them//recursive                    Target[name] = Jquery.extend (deep, clone, copy); Don ' t bring in undefined values//will eventually go to this branch//simple value override} else if ( Copy!== undefined) {Target[name] = copy; }}}}//Return the Modified object//Return the new target//If I < length is returned directly to the target not processed , that is arguments[0]//If you do not need to overwrite the source, call $.extend is actually to increase the static method of JQuery return target;};

It is important to note that this sentence jquery.extend = JQuery.fn.extend = function () {}, that is, the implementation of jquery.extend and the implementation of JQuery.fn.extend share the same method, but why it can be implemented Different features, thanks to Javascript's power (weird?). ) of this.

1) in Jquery.extend (), this point is the jquery object (or jquery Class), so it is expanded on jquery;

2) in JQuery.fn.extend (), the point of this is the FN object, which refers to Jquery.fn = Jquery.prototype, which is what is added here is the prototype method, which is the object method.

The chain invocation and backtracking of jQuery

Another reason to love using JQuery is because of its chained invocation, which is very simple to implement, just to return this in the return of the method to implement the chained call.

Of course, in addition to chained calls, jQuery even allows backtracking to look at:

Terminates the latest filter operation in the current chain through the end () method, returning the previous object collection $ (' div '). EQ (0). Show (). End (). EQ (1). Hide ();

When selected (' div '). EQ (0) after using end () to go back to the previous step of the selected JQuery object $ (' div '), its internal implementation is actually dependent on the addition of the Prevobject attribute:

JQuery Complete chain call, add stack, backtracking through return this, return This.pushstack (), return This.prevobject implementation, see the source implementation:

Jquery.fn = Jquery.prototype = {//Adds a collection of DOM elements to the jquery stack//This method is used frequently in the DOM operation of jquery, such as the parent (), find (), fi Lter () The//Pushstack () method tracks the DOM result set returned by the previous method in a chained call by changing the Prevobject property of a JQuery object//When we call the end () method in a chain, the internal returns the current JQ The Prevobject property of the Uery object Pushstack:function (elems) {//Build a new jquery object, no parameter This.constructor (), just return reference this/ /jquery.merge Merge the Elems node into the new jquery object//This.constructor is jquery's constructor jQuery.fn.init, so This.constructor () returns  Back to a JQuery object//Because the Jquery.merge function returns an object that is appended to the first one, RET is also a JQuery object, which explains why Pushstack DOM objects can also be used in CSS        method to operate var ret = Jquery.merge (This.constructor (), elems);        Adds a property to the new JQuery object returned Prevobject//so that is why the Prevobject can fetch the previous collection reference ret.prevobject = this;        Ret.context = This.context;    Return the newly-formed element set return ret; },//back-chaining the previous object End:function () {//The key to backtracking is to return the Prevobject property//And the Prevobject attribute is saved on theOne-Step JQuery object collection return This.prevobject | |    This.constructor (NULL);  },//Fetch the eq:function of the current jquery object (i) {//The length of a collection of jquery objects var len = this.length, j = +i        + (I < 0 len:0); Returning return This.pushstack with Pushstack (J >= 0 && J < len?    [This[j]]: []); }, }

Overall

1) The end () method returns the Prevobject property, which records the collection of JQuery objects in the previous operation;

2) While the Prevobject property is generated by the Pushstack () method, the method adds a collection of DOM elements to a stack within the jquery internal management by changing the Prevobject property of the jquery object to track the DOM returned by the previous method in the chained call Result set

3) When we call the end () method in a chain, the Prevobject property of the current JQuery object is returned internally to complete the backtracking.

Regularization and detail optimization

I have to mention that JQuery has done a good job in detail optimization. There are also a lot of tips to learn, and the next one will be the topic of some of the programming techniques in jQuery, which is not to be mentioned here.

Then I want to talk about regular expressions, and jquery uses a lot of regular expressions, I think if you study jquery, the regular level will be able to greatly improve, if it is a regular small white, I suggest to read the following before reading:

1) understand and attempt to use the Javascript regular related API, including the use of test (), replace (), match (), exec ();

2) distinguish the above 4 methods, which is the RegExp object method, which is the String object method;

3) Understand the simple 0-wide assertion to understand what captures but does not match and captures and matches.

Variable Conflict handling

Finally, I would like to mention the conflict handling of jQuery variables, by saving the Window.jquery and windw.$ of the global variables at the beginning.

When the conflict needs to be handled, call the static method Noconflict (), let the variable control, the source code is as follows:

(Function (window, undefined) {var//map over jQuery in case of overwrite//set alias, through two private variables mapped in window environment    JQuery and $ two objects to prevent variables from being forcibly overwritten _jquery = window.jquery, _$ = window.$; The Jquery.extend ({//Noconflict () method yields the jquery control of the variable $, so that other scripts can use it either//by using the full name instead of shorthand to use jquery//deep --Boolean value that indicates whether to allow the total use of the jquery variable to be restored (handing over the $ reference while handing over the jquery object itself) noconflict:function (deep) {//Determine if the global $ variable equals j                Query variable//If equal, then re-restore global variable $ for jquery before running the variable (stored in internal variable _$) if (window.$ = = = = JQuery) {            At this time JQuery alias $ invalid window.$ = _$; }//When deep conflict processing is turned on and the global variable jquery equals internal jquery, the global jquery is restored to the previous state if (depth && window.jquery = = = J            Query) {//If Deep is true, this time jQuery fails window.jquery = _jquery; }//This returns the jquery constructor inside the jquery library (new JQuery.fn.init ())//use it as much as you would with $ return jquery        ;  }  })} (window) 

Draw a simple flowchart to help understand:

After we have made these two symbols, is it possible to use jQuery or $ in our code? Not to panic, still can be used:

Giving up jquery, $ 's control does not mean that jquery and $ cannot be used, as follows: var query = Jquery.noconflict (True);(function ($) {//plug-in or other form of code, or you can set the parameter to Jque RY}) (query);//  ... Code for other libraries with $ as aliases
Conclusion

Some analysis of the overall architecture of jquery is here, and the next one will look at some of the optimization tips in jquery, some of the improvements in programming.

Original article, writing Limited, Caishuxueqian, if there is not in the text, million hope to inform.

Finally, I am on GitHub on the full text of the JQuery source code, interested can be onlookers, to a star. JQuery v1.10.2 source Annotations.

jquery Overall architecture Source code analysis

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.