A brief analysis of the source code of "simple and understandable jquery"--Overall structure

Source: Internet
Author: User
Tags instance method 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 uses a total-sub -structure, although JavaScript has a scope of the 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 ');

(Function (window, undefined) {var//... jquery = function (selector, context) {//The jquery object is actually just the It constructor ' enhanced '//See here, the instantiation method of JQuery () is actually called by its expanded prototype method JQuery.fn.initreturn new JQuery.fn.init (selector, context, rootjquery);},//Jquery.prototype is the prototype of jquery, mounted in the above method, you can make all the generated jQuery objects use Jquery.fn = Jquery.prototype = {//Real This 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 treated as a class and return a correct instance//And the instance will also have access to the properties on the JQuery class prototype correctly and method//jquery is the way to solve the problem through prototype delivery, the prototype of jquery passed to jquery.prototype.init.prototype//so the instance generated by this method is still pointing to the 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 () = = = 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 the collection of elements jquery ([Selector,[context]])//passing in a single Dom jquery (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 about 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 The method above (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 resolution is long, click below to expand, 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,target = Argume Nts[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, indicates whether to pass Return, if (typeof target = = = "Boolean") {deep = Target;target = Arguments[1] | | {};//Skip the Boolean and the target//if the first argument of type Boolean is passed, I is starting from 2 i = 2;} Handle case when the target is a string or something (possible in deep copy)//If the first argument passed is a string or another if (typeof target!== "ob Ject "&&!jquery.isfunction (target) {target = {};} Extend jquery itself if only one argument is passed//if the length of the parameter is 1, it is the jquery static method if (length = = = i) {target = this;--i;} Multiple replication sources can be passed in/I is 1 or 2 for (; i < length; i++) {//* deal with non-null/undefined values//copy the properties of each source to target if (options = arguments[i]) = null) {//Extend the base objectfor (name in options) {//SRC is the value of the source (i.e. itself)//copy is about to copy the past value s rc = Target[name];copy = options[name];//Prevent never-ending loop//prevents loops, such as extend (true, target, {' target ': target}); target = = copy) {continue;} Recurse if we ' re merging plain objects or arrays//here is a recursive call and will eventually go to the following else if branch//jquery.isplainobject to test whether it is purely an object//purely Object refers to the creation of a "{}" or "New Object"//If it is a deep copy if (Deeper && copy && (jquery.isplainobject (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//returns the new target//if I < length, is the direct return to the non-processed target, that is, arguments[0]//that is, if you do not pass the source to overwrite, call $.E Xtend is actually adding jQuery to the static method 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, Look at the source code implementation:

Jquery.fn = Jquery.prototype = {//Adds a collection of DOM elements to the jquery stack//This method is used frequently in jquery DOM operations, such as the parent (), find (), filter () The//Pushstack () method keeps track of 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, internally returns the Prevob of the current JQuery object Ject Property Pushstack:function (Elems) {//Build a new JQuery object, no parameter This.constructor (), just return reference this//jquery.merge merge Elems nodes into the new jquery object//This.constructor is the constructor jQuery.fn.init of jquery, so This.constructor () returns a JQuery object//Due to the object returned by the Jquery.merge function The second function is appended to the first, so RET is also a JQuery object, which explains why the Pushstack DOM object can also be manipulated using CSS methods var ret = Jquery.merge (This.constructor ( ), elems);//Adds a property to the new JQuery object returned prevobject//so that's why Prevobject can fetch a reference to the previous collection Ret.prevobject = This;ret.context = this.c ontext;//return the newly-formed element Setreturn ret;},//the previous object of the chain call End:function () {//The key to backtracking is to return the Prevobject attribute//And PR The Evobject property holds a collection of JQuery objects in the previous operation Return This.prevobject | | This.constructor (null);},//takes the current jquery object The first I eq:function (i) {////JQuery object collection length var len = tHis.length,j = +i + (i < 0? len:0);//returns return This.pushstack using Pushstack (J >= 0 && J < len?) [This[j]]: []);},}


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//sets the alias, maps JQuery and $ two objects in the window environment with two private variables to prevent The stop variable is forcibly overwritten _jquery = window.jquery,_$ = Window.$;jquery.extend ({//Noconflict () method gives out the variable $ of jQuery control so that other scripts can use it//replace by full name Shorthand way to use the jquery//Deep-Boolean value to indicate whether the jquery variable is allowed to be completely restored (handing over a $ reference while handing over the jquery object itself) noconflict:function (deep) {//Determine if the global $ variable equals jquery variable//If equal, then re-restores the global variable $ for jquery before running the variable (stored in internal variable _$) if (window.$ = = = jquery) {//At this time jquery alias $ invalidation window.$ = _$; }//when deep conflict processing is turned on and the global variable jquery equals internal jquery, then the global jquery is reverted to the previous condition if (depth && window.jquery = = = JQuery) {//If Deeper is Tru E, when 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 Jqu ery}) (query);//  ... Code for other libraries with $ as aliases

Concluding remarks

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.

If this article is helpful to you, please click on the recommendation, write the article is not easy.

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.

A brief analysis of the source code of "simple and understandable jquery"--Overall structure

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.