JQuery selector Code Description (5) -- describes the tokenize parsing process

Source: Internet
Author: User

JQuery selector Code Description (5) -- describes the tokenize parsing process

 

The following uses $ (div: not (. class: contain ('span '): eq (3) as an example to illustrate how tokenize and preFilter complete parsing. For more information about each line of code in the tokenize method and preFilter class, see the following two articles:

 

The following is the source code of the tokenize method. For the sake of simplicity, I have removed all the Code related to cache, comma matching, and link character matching, only the core Code related to the current example is left. The code to be removed is very simple. You can read the above article if necessary.

In addition, the Code is written at the top of the explanatory text.

 

function tokenize(selector, parseOnly) {var matched, match, tokens, type, soFar, groups, preFilters;soFar = selector;groups = [];preFilters = Expr.preFilter;while (soFar) {if (!matched) {groups.push(tokens = []);}matched = false;for (type in Expr.filter) {if ((match = matchExpr[type].exec(soFar))&& (!preFilters[type] || (match = preFilters[type](match)))) {matched = match.shift();tokens.push({value : matched,type : type,matches : match});soFar = soFar.slice(matched.length);}}if (!matched) {break;}}return parseOnly ? soFar.length : soFar ? Sizzle.error(selector) :tokenCache(selector, groups).slice(0);}

 

First, tokenize is called by the select method for the first time during jQuery execution, and div: not (. class: contain ('span '): eq (3) is passed in as the selector parameter.

 

soFar = selector;
SoFar = div: not (. class: contain ('span '): eq (3)

 

When you enter the while loop for the first time, because matched has not been assigned a value, execute the following statement body in the if statement. This statement will initialize the tokens variable and press tokens into the groups array.

groups.push(tokens = []);

 

Then, enter the for statement.

First for loop: extract the first element TAG from Expr. filter and assign it to the type variable to execute the loop body code.

 

if ((match = matchExpr[type].exec(soFar))&& (!preFilters[type] || (match = preFilters[type](match)))) {

 

The execution result of match = matchexpr1_type.exe c (soFar) is as follows:

Match = [div, div]

The first selector in the example is div, which matches the Regular Expression of matchExpr [TAG] and does not exist in the preFilters [TAG]. Therefore, the if statement body is executed.

 

matched = match.shift();
Remove the first element div in match and assign it to the matched variable. In this case, matched = div, match = [div]

 

 

tokens.push({value : matched,type : type,matches : match}
Create a new object {value: div, type: TAG, matches: [div]} and press the object into the tokens array.

 

 

soFar = soFar.slice(matched.length);
When the soFar variable deletes the div, soFar =: not (. class: contain ('span '): eq (3)

 

The second for loop: extract the second element CLASS from Expr. filter and assign it to the type variable to execute the loop body code.

 

if ((match = matchExpr[type].exec(soFar))&& (!preFilters[type] || (match = preFilters[type](match)))) {
Because the current soFar =: not (. class: contain ('span '): eq (3) does not match the regular expression of the CLASS type, this loop ends.

 

Third for loop: extract the third element from Expr. filter and assign ATTR to the type variable to execute the loop body code.

Similarly, because the current residual selector is not a property selector, this cycle ends.

The fourth for loop: extract the fourth element from Expr. filter and assign the CHILD element to the type variable to execute the loop body code.

Similarly, the cycle ends because the current residual selector is not a CHILD selector.

Fifth for loop: extract the fifth element from Expr. filter and assign the PSEUDO to the type variable to execute the loop body code.

 

if ((match = matchExpr[type].exec(soFar))&& (!preFilters[type] || (match = preFilters[type](match)))) {
The execution result of match = matchexpr1_type.exe c (soFar) is as follows:

 

[: Not (. class: contain ('span '): eq (3), not ,. class: contain ('span '): eq (3, undefined, undefined]

Because preFilters [PSEUDO do] exists, the following code is executed:

 

match = preFilters[type](match)
The preFilters [PSEUDO] Code is as follows:

 

 

PSEUDO : function(match) {var excess, unquoted = !match[5] && match[2];if (matchExpr[CHILD].test(match[0])) {return null;}if (match[3] && match[4] !== undefined) {match[2] = match[4];} else if (unquoted&& rpseudo.test(unquoted)&& (excess = tokenize(unquoted, true))&& (excess = unquoted.indexOf(), unquoted.length- excess)- unquoted.length)) {match[0] = match[0].slice(0, excess);match[2] = unquoted.slice(0, excess);}return match.slice(0, 3);}
The input match parameter is equal:

 

[: Not (. class: contain ('span '): eq (3), not ,. class: contain ('span '): eq (3, undefined, undefined]

 

unquoted = !match[5] && match[2]
Unquoted =. class: contain ('span '): eq (3

 

 

if (matchExpr[CHILD].test(match[0])) {return null;}
Match [0] =: not (. class: contain ('span '): eq (3). It does not match the matchExpr [CHILD] Regular Expression and does not execute the return null statement.

 

 

if (match[3] && match[4] !== undefined) {match[2] = match[4];}
Because match [3] and match [4] are both equal to undefined, the statement body that executes else.

 

 

else if (unquoted&& rpseudo.test(unquoted)&& (excess = tokenize(unquoted, true))&& (excess = unquoted.indexOf(), unquoted.length - excess) - unquoted.length)
At this time, unquoted =. class: contain ('span '): eq (3, true, and because unquoted contains: contain ('span'), it matches the regular expression rpseudo, so rpseudo. test (unquoted) is true, and then call tokenize to parse unquoted again, the following statement:

 

 

excess = tokenize(unquoted, true)
When the tokenize function is called this time, the input selector parameter is equal to. class: contain ('span '): eq (3, parseOnly is equal to true. The Execution Process in the function body is as follows:

 

 

soFar = selector;
SoFar =. class: contain ('span '): eq (3

 

 

When you enter the while loop for the first time, because matched has not been assigned a value, execute the following statement body in the if statement. This statement will initialize the tokens variable and press tokens into the groups array.

groups.push(tokens = []);

 

Then, enter the for statement.

First for loop: extract the first element TAG from Expr. filter and assign it to the type variable to execute the loop body code.

 

if ((match = matchExpr[type].exec(soFar))&& (!preFilters[type] || (match = preFilters[type](match)))) {
Because the current residual selector is not a TAG selector, this cycle ends.

The second for loop: extract the second element CLASS from Expr. filter and assign it to the type variable to execute the loop body code.

 

The execution result of match = matchexpr1_type.exe c (soFar) is as follows:

Match = [class, class]

Because preFilters [CLASS] does not exist, execute the if statement body.

matched = match.shift();
Remove the first element class in match and assign it to the matched variable. matched = class, match = [class]
tokens.push({value : matched,type : type,matches : match}
Create a new object {value: class, type: CLASS, matches: [class]} and press the object into the tokens array.
soFar = soFar.slice(matched.length);
When the soFar variable deletes the class, soFar =: contain ('span '): eq (3

Third for loop: extract the third element from Expr. filter and assign ATTR to the type variable to execute the loop body code.

Similarly, because the current residual selector is not a property selector, this cycle ends.

The fourth for loop: extract the fourth element from Expr. filter and assign the CHILD element to the type variable to execute the loop body code.

Similarly, the cycle ends because the current residual selector is not a CHILD selector.

Fifth for loop: extract the fifth element from Expr. filter and assign the PSEUDO to the type variable to execute the loop body code.

 

if ((match = matchExpr[type].exec(soFar))&& (!preFilters[type] || (match = preFilters[type](match)))) {
The execution result of match = matchexpr1_type.exe c (soFar) is as follows:

 

[: Contain ('span '), contain, 'span', ', span, undefined]

Because preFilters [PSEUDO do] exists, the following code is executed:

 

match = preFilters[type](match)
The preFilters [PSEUDO do] Code is shown above and will not be listed here.

 

PSEUDO : function(match) {var excess, unquoted = !match[5] && match[2];if (matchExpr[CHILD].test(match[0])) {return null;}if (match[3] && match[4] !== undefined) {match[2] = match[4];} else if (unquotedwww.bkjia.com&& rpseudo.test(unquoted)&& (excess = tokenize(unquoted, true))&& (excess = unquoted.indexOf(), unquoted.length- excess)- unquoted.length)) {match[0] = match[0].slice(0, excess);match[2] = unquoted.slice(0, excess);}return match.slice(0, 3);}
The input match parameter is equal:

 

[: Contain ('span '), contain, 'span', ', span, undefined]

 

unquoted = !match[5] && match[2];
Unquoted = span

 

 

if (matchExpr[CHILD].test(match[0])) {return null;}
Because: contain ('span ') does not match the matchExpr [CHILD] Regular Expression, internal statement bodies are not executed.

 

 

if (match[3] && match[4] !== undefined) {match[2] = match[4];}
Because match [3] = 'and match [4] = span, execute the if internal statement body and assign the span to match [2].

 

 

 

return match.slice(0, 3);

 

Returns a copy of the first three elements of a match.

Return to the for loop of the tokenize method and continue execution. The variable values are as follows:

Match = [: contain ('span '), contain, span]

SoFar =: contain ('span '): eq (3

 

matched = match.shift();
Remove the match array from the: contain ('span ') and assign the matched variable

 

 

tokens.push({value : matched,type : type,matches : match}
Create a new object {value: contain ('span '), type: PSEUDO, matches: [contain, span]}, and press the object into the tokens array.

 

 

soFar = soFar.slice(matched.length);
Delete soFar variable: contain ('span '). At this time, soFar =): eq (3), and then, until the for loop ends, and execute the while loop again, there is no valid selector, so the while loop is exited.

 

 

return parseOnly ? soFar.length : soFar ? Sizzle.error(selector) :tokenCache(selector, groups).slice(0);
Because parseOnly = true at this time, return the soFar length of 6 at this time, continue to execute the preFilters [PSEUDO do] Code

 

 

else if (unquoted&& rpseudo.test(unquoted)&& (excess = tokenize(unquoted, true))&& (excess = unquoted.indexOf(), unquoted.length - excess) - unquoted.length)
Assign 6 to the excess variable, and then the code
excess = unquoted.indexOf(), unquoted.length - excess) - unquoted.length

 

Calculated: not selector end position (that is, the right bracket position) 22

 

match[0] = match[0].slice(0, excess);match[2] = unquoted.slice(0, excess);
Calculate the complete: not selector string (match [0]) and the string in the brackets (match [2]), which are equal:

 

Match [0] =: not (. class: contain ('span '))

Match [2] =. class: contain ('span ')

 

return match.slice(0, 3);
Returns a copy of the first three elements in the match statement.

 

Return to the tokenize function. In this case, match = [: not (. class: contain ('span '), not,. class: contain ('span')]

 

matched = match.shift();
Remove the first element in match: not (. class: contain ('span '), and assign this element to the matched variable. matched =: not (. class: contain ('span ')),

 

Match = [not,. class: contain ('span ')]

 

tokens.push({value : matched,type : type,matches : match}
Create a new object {value: not (. class: contain ('span '), type: PSEUDO, matches: [not ,. class: contain ('span ')]}, and press the object into the tokens array. In this case, tokens has two elements: div and not selector.

 

 

soFar = soFar.slice(matched.length);
SoFar variable deletion: not (. class: contain ('span '). At this time, soFar =: eq (3) ends the for loop and returns to the while loop again. In the same way, obtain the eq selector, the third element of tokens. The process is the same as that of not. The final groups result is as follows:

Group [0] [0] = {value: div, type: TAG, matches: [div]}

Group [0] [1] = {value: not (. class: contain ('span '), type: PSEUDO, matches: [not ,. class: contain ('span ')]}

Group [0] [2] = {value: eq (3), type: PSEUDO, matches: [eq, 3]}

 

return parseOnly ? soFar.length : soFar ? Sizzle.error(selector) :tokenCache(selector, groups).slice(0);
Because parseOnly = undefined, tokenCache (selector, groups). slice (0) is executed. This statement pushes the groups into the cache and returns its copy.

 

As a result, after all the parsing is completed, someone may ask, the second element is not parsed here. Yes, this needs to be parsed again in actual operation. Of course, if you want to resolve this issue. class: contain ('span '): eq (3, save the results of the valid selector to the cache, so you can avoid re-parsing and improve the execution speed. However, this only increases the current running speed. During the execution process, when the. class: contain ('span ') is submitted for resolution again, it will be saved to the cache.

 

So far, the entire execution process has been completed.

 

 

Related Article

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.