Jquery source code analysis

Source: Internet
Author: User
Tags mootools

1. Overview
Jquery is a very good JS library. Compared with many JS class libraries such as prototype, Yui, and mootools, it is a powerful tool, starting from the practical point of view of web development, aside from some other useless items in Lib, it provides developers with a short and concise class library. It is short, concise, easy to use, efficient in performance, and can greatly improve the development efficiency. It is one of the best auxiliary tools for developing web applications. Therefore, most developers discard prototype and choose jquery for web development.
When using jquery, some developers often encounter many problems because they only know how to use jquery and do not understand the running principle of jquery. Most of these problems are caused by improper use, and few of them are jquery bugs. If you do not understand the running mechanism and core source code, it is difficult to write a high-performance Program .
When debugging A jquery-based program, we need to track the status of the jquery object for analysis most of the time, Code Unlike ext and Yui, its code is a bit obscure and hard to understand. That is to say, if you want to use jquery well, you must be clear about its source code.
Jquery has rich network resources, but Baidu has been around for a long time, but it is difficult to find a document that fully analyzes jquery source code. It is jquery's developer. John Resi's "Pro JavaScript techniques" involves the analysis of jquery's source code. It can be seen as jquery's source code analysis, but it mainly refers to the use of JavaScript. We do not understand it very well. We carefully understand the jquery source code.

2. jquery object
In this section, we will analyze and describe the jquery operating mechanism and design concept. This section consists of jquery's system, construction, and array features.
2.1 jquery Design Philosophy
Before using jquery, we all ask what jquery is? Jquery is a class library that provides auxiliary functions for Web JS development like prototype and mootools. So why jquery? Before jquery appeared, prototype and Yui were all mature JS frameworks with different characteristics. Why abandon them and use jquery, which is an outstanding feature, to attract developers?
To answer this question, we must understand jquery's design philosophy. Recall or imagine how we use Js in Web development? Most of the time, getelementbyid is used to find the DOM element in the DOM document, and then the value or set value, innerhtml is used to retrieve or set its content, or event listening (such as click ), in terms of style control, we will change the height, width, and display to achieve visual effect. For Ajax, it is also used to add content to an element of the page.
To sum up, we are operating the DOM elements. This element may be one or more. This element may be a document, window, or DOM element. In this way, our task is the second largest part. One is to find the DOM element, and the other is to operate the DOM element.
Be familiar with it, whether using direct search like getelementbyid or using element. the indirect search methods such as lastchild are not very difficult. For Dom elements, Dom operations are also very rich and not very difficult to use? So what is the use of the Class Library? The most difficult problem is browser compatibility. All JS frameworks must solve this problem and simplify the built-in operations of Js.
Prototype can be said to have created a precedent for JS class libraries, giving us a fresh feeling. It solves the compatibility issues of most browsers. At the same time, it simplifies the issue of errors written by regular books with long and difficult to remember original function names (replacing getelementbyid with $ (XX), provides Ajax access, extends array, object, functions, events, and other JS native objects.
But these still cannot meet the development needs. For example, to search for DOM elements in the DOM tree, we can only use the element ID, but we want a more convenient search method, at the same time, we also hope to have a unified entrance. The learning curve is too high or difficult to use.
Jquery is here to unify everything in the jquery object. Jquery objects are used. In fact, jquery's pioneering work is like its name: query. Its powerful search function eclipses all frameworks.
Jquery is actually a queryer. On the basis of the queryer, you can also perform operations on the searched elements. In this way, jquery is the unified query and operation. Queries are portals and operations are results.

Jquery can also be divided into two parts in implementation. One part is jquery's static method, which can also be called a practical method or a tool method. It is directly referenced through the jquery namespace of jquery. XXX. The second part is the jquery instance method. The jquery instance is generated through jquery (XX) or $ (XX) and then referenced through this instance. Most of these methods are implemented by using static method proxies. Real functional operations are implemented in jquery's static method.
These functions are subdivided into the following parts:
1. selector: Find the element. This search not only contains ~ CSS selector of css3 also includes some functions that can be extended for direct or indirect searches.
2. Attribute operations on DOM elements. DOM elements can be viewed as HTML tags. Operations on attributes are operations on the attributes of tags. This attribute operation includes addition, modification, deletion, and value.
3. Operations on CSS styles of DOM elements. CSS controls the display of pages. Operations on CSS must include common CSS functions such as height, width, and display.
4. Ajax operations. Ajax is used to asynchronously fetch data from the server and perform related operations.
5. Event operations. Unified processing of event compatibility.
6. animation (FX) operations. It can be seen as an extension of CSS styles.

2.2. jquery Object Construction
Generating or constructing a jquery object is actually building and running a selector ). Since it is a query, the results (DOM element) will certainly be searched before these results will be operated. So where are the search results stored? The best part is, of course, the inside of the jquery object. The search result may be an element or multiple elements, for example, a nodeset set ). That is to say, there is a set inside the jquery object. This collection stores the DOM elements found.
But the jquery object mentioned in the previous section is the unified entry for all operations, so its construction cannot be limited to finding Dom elements from the DOM document, it may also be a DOM element transferred from another collection, or a DOM element generated from an HTML string.
The jquery document provides four methods: jquery (expression, [Context]), jquery (HTML), jquery (elements), and jquery (callback) there are four ways to create jquery objects. Jquery can be replaced by $. These four types are frequently used. In fact, jquery parameters can be any element and can constitute jquery objects.
For example:
1. $ ("P") shows that its parameters can be a set of jquery objects or arraylike.
2. $ () is short for $ (document.
3. $ (3) puts 3 in a collection of jquery objects.
For elements such as $ (3), such as elements in the arraylike set, are not DOM elements. We recommend that you do not construct jquery objects. jquery object methods are applicable to DOM objects. If you do not know how to use it, it is likely to cause errors.

As mentioned above, it is still difficult to understand its principles. Now we will analyze it from the source code perspective:
No object is generated by calling jquery (XXX), and this of it points to the window object. So how do jquery's instance methods inherit from them? Take a look:
VaR jquery = Window. jquery = Window. $ = function (selector, context) {return New jquery. FN. INIT (selector, context); ①
};
This is the general entry of jquery. jquery objects do not actually inherit the methods in their prototype through new jquery. The jquery object is actually the object generated by the jquery. FN. init function. We can see that it is of little significance to add some function set objects for jquery. prototype. Because we can use new jquery (), but the generated jquery object will be discarded at return. Therefore, it is best not to use new jquery () to construct jquery objects.
The jquery object is actually new jquery. FN. init. Therefore, jquery. FN. init. prototype is the operation method for hanging jquery objects. For example
Jquery. FN. init. Prototype = jquery. FN;
There may be time to worry about implementing jquery in line 589. put the function in FN in jquery. FN. init. prototype, then use jquery. FN. what should I do with the extend method? Here is actually a reference to jquery. fn. When extending jquery, you only need to extend the relevant function extend to jquery. fn.
Now let's take a look at how jquery. FN. init completes the work:
Init: function (selector, context ){
Selector = selector | document; // determines whether the selector exists.
// In the first case, handle $ (domelement) indicates a single Dom element, ignoring the context
If (selector. nodetype) {②
This [0] = selector;
This. Length = 1;
Return this;
}
If (typeof selector = "string") {// selector is string ③
VaR match = quickexpr.exe C (selector );
If (match & (Match [1] |! Context )){
If (Match [1]) // process the second case $ (HTML)-> $ (array) ④
Selector = jquery. Clean ([Match [1], context );
Else {// Case 3: handle: $ ("# ID") // process $ ("# ID ")
VaR ELEM = Document. getelementbyid (Match [3]);
If (ELEM ){
// Ie returns the name = ID element. If so, document. Find (s)
If (ELEM. ID! = Match [3]) ⑤
Return jquery (). Find (selector );
// Construct a new jquery (ELEM)
Return jquery (ELEM); ⑥
}
Selector = [];
}
} Else
// Case 4: Processing $ (expr, [Context]) =$ (content). Find (expr)
Return jquery (context). Find (selector); 7
} Else if (jquery. isfunction (selector) else // case 5: Processing $ (function) shortcut for document ready
Return jquery (document) [jquery. FN. Ready? "Ready": "LOAD"] (selector );
// Case 6: Process $ (elements)
Return this. setarray (jquery. makearray (selector); optional
},
Jquery. FN. init analyzes the passed parameters and generates jquery objects. Its first parameter is generally required (if it is null, It is the default document ). From the source code perspective, the first parameter has the following four types:

Type description
Dom Element
The first parameter is the DOM element, and the second parameter is not required. Directly store the DOM element in the collection of newly generated jquery objects. Returns the jquery object. The jquery object is built.

String
The first parameter is string in three cases:
1. The tag string of HTML, $ (HTML)-> $ (array). The second parameter is optional.
Run selector = jquery. Clean ([Match [1], context );. This statement converts a hteml string to an array of DOM objects. Then, return the array type.
2. When the string is # ID $ (ID)
First, use VaR ELEM = Document. getelementbyid (Match [3]); To obtain ELEM. If selector = [] is not obtained, the returned empty set jquery object of array type is transferred.
For example, if ELEM is found, the jquery object is generated again through return jquery (ELEM); this is the return of the jquery object of the DOM element type.
3. selector string compatible with the css1-3 syntax, the second parameter is optional. Run return jquery (context). Find (selector );. This statement runs jquery (context) first ). We can see that the second parameter of context can be any value or a set form. Then, we can use find (selector) to find a set of DOM elements in jquery (context) that satisfy the selector expression, construct a new jquery object, and return the result.
# ID is actually consistent with this method. It is used separately to improve performance.


FN

The first parameter is the function. The second parameter is not required. Is short for $ (document). Ready (FN). Its return jquery (document) [jquery. FN. Ready? "Ready": "LOAD"] (selector) is the code it executes. This statement first executes jquery (document). It returns the newjquery. FN. init function to generate a jquery object (the element is document ). Call the ready (FN) method of this object. Ready (FN) returns the current object. The preceding statement returns the returned object of this ready (FN.
As you can see, $ (FN) returns the $ (document) object. The $ (FN) object generated for the first time is discarded.



Array
The first parameter is all types except the DOM elements, functions, and strings mentioned above. It can be null, for example, $ (). The second parameter is not required.
Statement: return this. setarray (jquery. makearray (selector ));
It first converts the first parameter to an array. Selector can be an array-like set, such as a jquery object, such as a DOM Element Set returned by getelementsbytag, and may support $ (this ). Selector may also be a single arbitrary object.
After being converted to a standard array, execute this. setarray to save all the elements in this array to the current jquery object set. Then, the current jquery object is returned.
In fact, DOM elements may be integrated here, which can be taken separately to improve performance.


From the code above and the above table, we can also see that building a jquery object is to add elements to the collection of jquery objects (usually DOM elements ). The added element has two forms:
One is a single element. It may be in the form of passing parameters of the DOM element directly. You can also use # ID to find the element from the DOM document.
Second, collections, such as jquery objects, arrays, Dom sets found through CSS selector, and other array-like.
The above table only analyzes the type of the input parameter. How can this problem be solved? In step 5, it implements css1 ~ Css3 is compatible with selector lookup functions. Use jquery (). Find (selector); to analyze the string and find the element set in the DOM document tree that complies with the passed selector syntax.
At ④, it converts HTML strings into a collection of Dom element nodes. This is achieved through jquery. Clean ([Match [1], context.
At the handler, it implements the unified entry of domready's jquery object. We can use $ (FN) to register domready's listening function. All functional code that calls jquery should be run after domready. $ (FN) is the entry to all functional code in application development. It supports any number of $ (FN) registrations. Return jquery (document) [jquery. FN. Ready? "Ready": "LOAD"] (selector.
After the element is found, the set is constructed. In the set, the set is constructed through this. setarray (jquery. makearray (selector. The following section analyzes how the set is implemented.

2.3 array features of jquery objects
From the above section, we can see that jquery builds a function to complete the search, conversion, or other functions. The result is to find the elements, search, and search, which is just a way. You have to find a place to store the elements. This section is for analysis.
The best place (SET) for storing ordered data in JS is array. So how can we implement arrays in jquery? You can use the following method:
Jquery. FN. Prototype = new array ();
In the this. setarray (ARR) function in the previous section, add
Array. Apply (this, arr );
If it is more perfect, add:
Jquery. FN. Prototype. constructor = jquery.
In this way, we inherit all the features of the array and can extend the Array Function in the jquery object. However, jquery does not use the inherited array to implement this internal set. It uses the implementation of the array-like object (see javascript: the definitive guide, 5th edition7.8 ).
The object of the class array is still an object, just like an array. There is no big difference between arrays and objects. Ordered and unordered sets are different from each other. This difference is reflected in the Length attribute of the array. When an element is added, the relative number is automatically added. When an element is deleted, the relative number is automatically subtracted.
Let's take a look at how jquery is implemented:
// In the first case, handle $ (domelement) indicates a single Dom element, ignoring the context
If (selector. nodetype) {②
This [0] = selector;
This. Length = 1;
Return this;
}
This is its first implementation method. This [0] is used to directly set the DOM element at the first position and set length = 1. Here we can see that the object and the array both use the key/value pair form to exist in the object. The preceding JSON format is {0: Adom, length = 1 }. Here we will analyze the array in detail. The array inherits from the object. The final result of its [] interpretation analysis can be considered as an object of {} structure. Index (such as 0.1,…) will be carried out during the construction of [] or array ,....) As the key of the object property. Use the values in the array as their corresponding values. Change the length value at the same time. That is why objects are essentially no different from arrays. In many source codes, for example, Yui uses objects to construct multidimensional arrays.
This. setarray (jquery. makearray (selector ));
Is its second implementation method. The above implementation is a single element, a set of multiple elements of this implementation. It first calls the jquery. makearray (selector) Static Method to convert the Set (class array) into an array.
The above analysis shows that both arrays and objects can use obj. [ATTR] to obtain the value corresponding to their key. For a set or an array of classes, the Length attribute must be implemented. With the Length attribute, the length ranges from 0 ~ You can get the corresponding value in the key attribute of length-1:
// Convert the set of class arrays into an array. If it is a single element, an array of a single element is generated.
Makearray: function (array ){
VaR ret = [];
If (array! = NULL) {var I = array. length;
// A single element, but the window, string, and function have the 'length' attribute. Add other judgments.
If (I = NULL | array. Split | array. setinterval | array. Call)
RET [0] = array;
Else // a set of class Arrays
While (I) RET [-- I] = array [I]; // clone Array
}
Return ret;
},
A standard array is generated. What will setarray do next?
// Push all elements of the array-like object to the current jquery object.
Setarray: function (elems ){
This. Length = 0; // initialization length, because the push will be in the original length ++
Array. Prototype. Push. Apply (this, elems );
Return this;
},
This call calls array. Prototype. Push to automatically modify the Length attribute value (of course, an element is added ). As a result, many methods (such as shift) in the array can be seen as changing the value of length to the key/value pair of the object to complete unordered or re-ordered work. In fact, array and so on are implemented using C or C ++. However, the JS features it constructs allow us to think about how Javascript is implemented.
The above setarray (elems) function only changes the set of the current jquery object and clears the previous elements in this object set. However, sometimes we want to save the elements in the original collection and perform jquery object operations on the new elements. It provides the pushstack function to create a new jquery object and save the reference of the original object. In this way, you may use the objects you want as needed:
Pushstack: function (elems) {// use jquery to build new objects and reference old objects.
VaR ret = jquery (elems); // construct a new jquery object
Ret. prevobject = This; // Save the reference of the old object
Return ret;
},
The returned result is a newly built object with all the functions of the jquery object. You can also use prevobject to access the original old object.

If a class array is built, you must provide some methods to operate on this set. operations on the set are nothing more than locating elements, searching elements, copying (slice), and deleting operations (SPLICE. Jquery also provides each and map extensions.
These methods are only related to the set and are irrelevant to the set elements. Jquery provides many methods related to the element (DOM element.

It provides two get element methods, get (INDEX) and eq (INDEX). The difference is that get is an element in the Set, while EQ is the clone of the returned element. The array is not modified. In fact, you can use [I] instead of get (I ). If get does not have a parameter, all elements are obtained.
// Obtain the several DOM elements of the jquery object. No parameter exists, indicating all DOM elements.
Get: function (Num ){
Return num = undefined? Jquery. makearray (this): This [num];
},
// Obtain the nth element. The position of this element is counted from 0.
EQ: function (I ){
Return this. Slice (I, + I + 1 );
},
These two functions do not need to be analyzed. Next, let's take a look at how to locate elements in the collection:
/Locate the location of elem in the jquery object (INDEX)
Index: function (ELEM ){
VaR ret =-1;
Return jquery. inarray (// If the jquery object is used, obtain the first element.
ELEM & ELEM. jquery? ELEM [0]: ELEM, this );
},

// Determine the location (INDEX) Static Method of the ELEM element in the array
Inarray: function (ELEM, array ){
For (VAR I = 0, length = array. length; I <length; I ++)
// Use === because on IE, window = Document
If (array [I] === ELEM)
Return I;
Return-1;
},
Inarray is the static method of jquery, while index is the function of positioning by calling inarray. The index function supports jquery objects or DOM elements, while inarray is a practical method that supports any element.

Jquery provides methods such as the Server Load balancer replication function in the array, and a static merge method similar to Concat. Slice is implemented through slice in array:
/Proxy array slice, the same operation.
Slice: function (){
Return this. pushstack (array. Prototype. Slice. Apply (this, arguments ));
},
It returns a new jquery object. The set of this object is the set to be copied. For merge, It is a static method that adds the second element to the array of the first parameter.
// Append the second element to the first array.
Merge: function (first, second ){
// We have to loop this way because IE & opera overwrite the length
// Expando of getelementsbytagname
VaR I = 0, ELEM, Pos = first. length;
// Also, we need to make sure that the correct elements are being
// Returned (ie returns comment nodes in a '*' query)
If (jquery. browser. MSIE ){
While (ELEM = Second [I ++])
If (ELEM. nodetype! = 8)
First [POS ++] = ELEM;

} Else
While (ELEM = Second [I ++])
First [POS ++] = ELEM;

Return first;
},
Jquery's each performs a callback function for each element in the set.
// The callback (index, ELEM) function is executed for each element of the current jquery object.
Each: function (callback, argS) {// returns this
// It calls the jquery static method. Mothodize in prototype is a good solution to this type of problem.
Return jquery. Each (this, callback, argS );
},
It calls the jquery. Each static method to complete the function:
// Execute the callback function for each object. ARGs is only used internally
Each: function (object, callback, argS ){
VaR name, I = 0, length = object. length;
// It is similar to else processing. The args parameter passing replaces the object attribute value.
If (ARGs ){
If (length = undefined ){
For (name in object)
If (callback. Apply (object [name], argS) === false)
Break;
} Else
For (; I <length ;)
If (callback. Apply (object [I ++], argS) === false)
Break;
} Else {
// Not an array-like object. Call the callback function for each attribute.
If (length = undefined ){
For (name in object)
If (callback. Call (object [name], name, object [name]) === false)
Break;
} Else
// Array-like object, which is processed as an array
For (VaR value = object [0]; I <length & callback. Call (value, I, value )! = False; value = object [++ I]) {}
}
Return object;
},
This static method supports the class array (array) or object of the first parameter. Is an array to call back each element. If it is an object, the callback operation is performed on each attribute value. The format of this callback function is as follows: callback: function (index, value ). Index is the index number, and value is the index processing attribute of the element or object corresponding to the index of the array. If the ARGs parameter is used, the callback function format is as follows: callback: function (ARGs ). ARGs sets parameters for the callback function. Let's take a look at the each of the jquery object. Its second parameter, argS, uses the input ARGs to directly set parameters for callback, instead of raising the index and corresponding elements in the set by default, but the number of executions is still the length of the set.

Jquery map converts a group of elements into other arrays (composed of callback function return values) // convert a group of elements into other arrays and then construct a new jquery object based on the array ..
Map: function (callback ){
Return this. pushstack (jquery. Map (this, function (ELEM, I ){
Return callback. Call (ELEM, I, ELEM );
}));
},
This function first uses jquery. Map (this, function (ELEM, I) {} to upload each element of this's jquery object set as the ELEM parameter of the callback function to the callback function. The callback function executes the callback function in the MAP: function (callback) of the instance method, that is, the callback in jquery. MAP is only the function of passing the parameter proxy. Jquery. Map gets the converted element set through the callback of the proxy.
The next step is to use pushstack to construct the elements in this set into a new jquery object and return it, and save the reference of the original jquery object.
Let's take a look at the static method of MAP:
// Return the set of return values of the callback function that operates on each element of elems.
Map: function (elems, callback ){
VaR ret = [];
For (VAR I = 0, length = elems. length; I <length; I ++ ){
VaR value = callback (elems [I], I );
If (value! = NULL) // indicates that the number of converted sets may be less than that of the original set.
RET [ret. Length] = value;
}
Return ret. Concat. Apply ([], RET); // use the Concat of array to implement
}
The static method of map returns an array composed of elements returned by each callback.

This article from the csdn blog, reproduced please indicate the source: http://blog.csdn.net/liuwei_blog/archive/2008/11/25/3366942.aspx

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.