JQuery constructor init parameter analysis continued
In fact, F and jQuery. fn. init is equal. The implementation function is the same as jq, but jq puts the constructor into the prototype. If you have to say the reason, I understand that the overall structure of jq is clear, first, the entry constructor is followed by the prototype part (in the prototype, init is initialized), but it is hard to understand. At first glance, it is really difficult to understand what is going on.
If selector is another string, it is more complicated.
?
1 2 |
// Handle HTML strings If (typeof selector = "string "){...} |
Start to process different situations
?
1 2 3 4 5 6 7 |
// Are we dealing with HTML string or an ID? If (selector. charAt (0) = "<" & selector. charAt (selector. length-1) ==="> "& selector. length> = 3 ){ // Assume that strings that start and end with <> are HTML and skip the regex check Match = [null, selector, null]; } Else { Match = quickExpr.exe c (selector ); } |
If the first character is "<" and the last character is ">" and the length is greater than 3, it is assumed that the selector is a simple html Tag, for example, $ ('
') But remember to only assume that "assume" for example $ (' . Then, modify the match array to [null, selector, null]. Here, match is the variable declared in the init function, it is mainly used as a tool to differentiate between parameter types and list possible situations later. The following are the four variables declared in the source code.
?
1 2 |
Init: function (selector, context, rootjQuery ){ Var match, elem, ret, doc; |
If the if condition is not met, a regular expression is called to obtain the match result. quickExpr is the variable declared in the jQuery constructor.
?
1 2 3 |
// A simple way to check for HTML strings or ID strings // Prioritize # id over <tag> to avoid XSS via location. hash (#9521) QuickExpr =/^ (? : [^ # <] * (<[\ W \ W] +>) [^>] * $ | # ([\ w \-] *) $ )/, |
This regular expression is mainly used to distinguish between html strings and id strings. The second comment explains how to avoid location-based. hash XSS attacks, so the # (#9521) added in quickExpr means that we can find relevant explanations on the jQuery official website.
First, visit http://bugs.jquery.com/and then search for the corresponding value.
The execution result of quickExpr.exe c (selector) can be an array. The first element of the array is the matching element, and the rest are the group matching elements, this regular expression has two groups (<[\ w \ W] +>) [^>] and ([\ w \-] *). One is the tag and the other is the id value. The results will be handed over to match. Next we will analyze the various situations of match. First, the regular expression [null, selector, null] is not used for a single tag. The following code proves that:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<! Doctype html> <Html> <Head> <Title> </title> <Script src = 'jquery-1.7.1.js'> </script> </Head> <Body> <Div id = 'div '> </div> </Body> <Script> $ ('<Div> '); </Script> </Html> |
In html, we create a jQuery object and output the match result in the init method:
?
1 2 3 4 5 6 7 |
If (selector. charAt (0) = "<" & selector. charAt (selector. length-1) ==="> "& selector. length> = 3 ){ // Assume that strings that start and end with <> are HTML and skip the regex check Match = [null, selector, null]; } Else { Match = quickExpr.exe c (selector ); } Console. log (match); // [null, "<div>", null]; |
Next, modify the parameter to $ ('# div') and then read the result.
The Code is as follows:
["# Div", undefined, "div", index: 0, input: "# div"]
There is also a special case $ ('
123 ') Then let's look at the result.
The Code is as follows:
["
Dewrwe ","
", Undefined, index: 0, input :"
Dewrwe "]
We can see that the id is always in the third element and the tag value is stored in the second element. For the last case ('
') There is no difference because the first element is not processed when the dom element is generated. Based on this result, we can analyze the next judgment.
Next, we will divide the matching results into three situations.
?
1 2 3 4 5 6 7 8 9 10 11 12 13 |
If (match & (match [1] |! Context )){ ... } Else if (! Context | context. jquery ){ ... } Else { ... } |
The first condition is that match must have a value. match [1] means that the second element is to save the value of the tag or there is no context, but it seems that there is no id? In fact, It is not through the analysis of the match result that we can know that the result of the second element without a value is definitely the id selector, And the id is unique, no need to write the context (in fact, the context will be normally executed, but Sizzle will be used instead of processing the same content as the body here ). Okay, the first condition is
1. Tag
$ ('
') $ ('
123 ') $ ('
23213213
')...
2. No context id $ ('# div ')
The first condition is further subdivided:
?
1 2 3 4 5 6 7 8 9 10 |
// HANDLE: $ (html)-> $ (array) If (match [1]) { ... // HANDLE: $ ("# id ") } Else { } |
Obviously, if the else for processing tags is processing IDs, let's take a look at how to process tags first.
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Context = context instanceof jQuery? Context [0]: context; Doc = (context? Context. ownerDocument | context: document ); // If a single string is passed in and it's a single tag // Just do a createElement and skip the rest Ret = rsingleTag.exe c (selector ); If (ret ){ If (jQuery. isPlainObject (context )){ Selector = [document. createElement (ret [1])]; JQuery. fn. attr. call (selector, context, true ); } Else { Selector = [doc. createElement (ret [1])]; } } Else { Ret = jQuery. buildFragment ([match [1], [doc]); Selector = (ret. cacheable? JQuery. clone (ret. fragment): ret. fragment). childNodes; } Return jQuery. merge (this, selector ); |
First, modify the value of context. If it is a jQuery object, convert it into a dom element, that is, use the underlying method. This principle has been mentioned before, and then the doc variable is processed, if the context does not exist, assign the document value to the doc. If there is an ownerDocument attribute, It is the dom element. The value is also the document. If it is not a dom element, such as a common js object, assign a value to this object. to the doc variable. Then a regular expression is made to the selector. This regular expression is also declared in the jQuery constructor to determine a single tag, such
Such
The Code is as follows:
// Match a standalone tag
RsingleTag =/^ <(\ w +) \ s * \/?> (? : <\/\ 1> )? $ /,
Then, hand over the result to the ret variable, the ret-based value is further divided. The ret value is processed separately based on the single tag and the complex tag. The existence of the ret value is that a single tag is matched and then the isPlainObject is detected based on whether the context is a common object. methods of common objects, if it is a common object, the native method of js createElement is used to pass in the tag to create elements and put them in an array. The reason for this is to facilitate merging with the jquery object and then assign the array to the selector, then, the attr method is called using the object impersonating method. Here, attr actually has three parameters, and the APIS we normally use are two parameters. In fact, there are many similar situations in jQuery, the same method has two internal and external interfaces. The second parameter is the context in the object format, because attr can
The Code is as follows:
$ ("Img"). attr ({src: "test.jpg", alt: "Test Image "});
This is actually what we can do later $ ('
', {Id: 'div. If it is not an object, directly create an element without considering attributes. Put the created elements in the array. If ret has no value, it is a complicated tag, for example, $ ('
231
') In this case, the native js may not be able to solve the problem. We need to call another method jQuery. buildFragment for processing. This method will be learned in the future. In the end, we will create dom elements. Returns the merged result.
The Code is as follows:
Return jQuery. merge (this, selector );
Unlike the previous return this, here is the result of merge's execution. In fact, his job is to merge the created dom elements in the array into the jquery element, and finally convert it to {0: div, length: 1 ...} such an object form. In this case, the simple tag is processed.
The else then processes the id information.
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Elem = document. getElementById (match [2]); // Check parentNode to catch when Blackberry 4.6 returns // Nodes that are no longer in the document #6963 If (elem & elem. parentNode ){ // Handle the case where IE and Opera return items // By name instead of ID If (elem. id! = Match [2]) { Return rootjQuery. find (selector ); } // Otherwise, we inject the element directly into the jQuery object This. length = 1; This [0] = elem; } This. context = document; This. selector = selector; Return this; |
It is easy to directly call the id selector of native js, but some systems may encounter bugs.
Note that the BlackBerry system clearly states that the elements do not exist but can still be matched. Therefore, when the parent node is added, the nonexistent elements certainly do not have the parent node. Another case is that ie and operabrowser will match by name. Therefore, a judgment is made.
If (elem. id! = Match [2]) {
If unfortunately, the native method cannot be used, but the find method is used, that is, the sizzle engine, in most cases, you can directly put the obtained elements in this and modify the value of context. OK, the first big branch is finally analyzed. Then, let's look at the second branch of the match.
?
1 2 3 |
Else if (! Context | context. jquery ){ Return (context | rootjQuery). find (selector ); } |
Here, if there is no context or the context is a jquery object, it is relatively simple to use the find method directly. rootjQuery is $ (document)
Otherwise
The Code is as follows:
Return this. constructor (context). find (selector );
This. constructor is jQuery but still uses the find method.
The above is all the content of this article. I hope you will like it.