Original articles, reproduced please specify the source, thank you!
/* * The Tokenize function is the core function of the selector resolution, which converts the selector to a two-level array groups * Example: * If the selector is "Div.class,span", then the parsed result is: * group[0][0] = {type: ' TAG ', Value: ' div ', matches:match} * group[0][1] = {type: ' class ', Value: '. Class ', Matches:match} * group[1][0] = {type: ' TAG ' , value: ' Span ', matches:match} * from the above results can be seen, groups each meta-comma-delimited selector block resolution results, * In addition, the above results in matches equals pattern matching results, because this inconvenient to write clearly, * So just write the code matches:match here. * * @param selector The selector string to be parsed * @param parseonly is true, this call is a matching sub-selector * For example: If the initial selector is "Div:not (. Class:not (: eq (4)): EQ ( 3) "* Code first matches the tag Selector Div, * after matching the pseudo selector string is: Not (. Class:not (: eq (4))): EQ (3), * code will put". Class:not (: eq (4)): EQ (3) as Further parsing is performed for values within the parentheses of not, and the parseonly parameter is passed to true when the code calls Tokenize resolution. */function tokenize (Selector, parseonly) {var matched, match, tokens, type, sofar, groups, prefilters,//Get results in cache cached = Tokencache[selector + ""];/* * if the cache has selector corresponding parsing results * Then execute if in the statement body */if (cached) {//If the initial selector resolution (PARSEONLY!=TRUE), then return the cached results,// If not, return 0return parseonly? 0:cached.slice (0);} /* * Due to string in JAVASCRIThe PT is not handled as an object, * so by assigning a value, the code automatically copies a new string to Sofar, * so that any processing of SOFAR does not affect selector's original data */sofar = Selector;groups = [];//is assigned here , only to reduce the number of subsequent code words, shorten the execution path prefilters = Expr.prefilter;while (sofar) {//Comma and First run/* * Rcomma = new RegExp ("^" + whites Pace + "*," + whitespace + "*") * Rcomma is used to determine if there are multiple selector blocks, that is, multiple selectors separated by commas * * The following conditions are determined: *!matched: True if the loop body is executed for the first time; otherwise FAL Se * Here matched is as the first time to execute the identity of the loop body, * Also as the sofar in this cycle is an illegal string (that is, the non-legitimate single selector) the beginning of the flag. * (match = rcomma.exec (Sofar): Gets matching Rcomma matches */if (!matched | | (match = Rcomma.exec (Sofar))) {if (match) {//Don ' t consume trailing commas as valid/* * Remove the first comma and all previous characters * For example: * If the initial selector is: "div.news,span.closed", * in the solution Analysis process, the first by the subsequent code parsing completed div.news, the remaining ", span.closed" * In the loop body execution here, the comma and before the continuous white space (match[0]) removed, * so that the sofar into "span.closed", Continue the parsing process * Here, if the last non-whitespace character of the initial selector is a comma, * then the following code is executed Sofar, that is, Sofar.slice (match[0].length) returns an empty string, * So the final return is | | The back of Sofar */sofar = Sofar.slice (match[0].length) | | Sofar;} /* * In the first execution of the loop body or when a comma delimiter is encountered, tokens is assigned to an empty array, * simultaneously pressed into the groups numberGroup */groups.push (tokens = []);} matched = false;//combinators/* * rcombinators = new RegExp (* "^" + whitespace + "* ([>+~]|" + whitespace + ")" + White Space + "*"), * rcombinators is used to match four types of relationships, i.e. >+~ and whitespace * * If the SOFAR is started with a relationship, then the statement body */if (match = rcombinators.exec (Sofar)) within if is executed {/* * Match[0] removes the match array and assigns it to matched * If the original relationship has spaces on either side, then match[0] is not equal to matched * For example: * If Sofar = "+. Div"; * Perform match = Rcombinators.exec (SOFAR), * match[0] = "+", while match[1]= "+"; * After executing matched = Match.shift (), * matched= "+", while match[0]= "+"; */matched = Match.shift ();//press the match result into the tokens array Tokens.push ({value:matched,//Cast descendant combinators to space/* * Rtri m = new RegExp ("^" + whitespace + "+| ( (?:^| [^\\\\]) (?:\ \\\.) *) "*+ whitespace +" +$ "," G "), * whitespace =" [\\x20\\t\\r\\n\\f] "; * * Below Match[0].replace (RTrim, "") is the role of match[0] left and right side of the white space is replaced with a space * but because of its role in the Match.shift, Match[0] is already on both sides of the string without whitespace, * The substitution is therefore no use of code */type:match[0].replace (RTrim, "")});//Assign the string after the relationship to Sofar, continue parsing sofar = Sofar.slice (matched.length);} //filters/* * The selector for SOFAR-match ID, TAG, CLASS, child, ATTR, pseudo type is called by the For statement, and the pre-filter function corresponding to the type selector is invoked first, * Then the result is pressed into the tokens array, Continue this cycle. */for (type in expr.filter) {/* * match = matchexpr[type].exec (SOFAR): a regular expression that calls the type of the SOFAR is matched to Sofar, * and the matching result is given to match. If the data is not matched, match is undefined. *!prefilters[type]: true * match = Prefilters[type] (match): Performs pre-filtering and returns the result to match * */if ((match = Matche) If there is no pre-filter function of type. Xpr[type].exec (Sofar) && (!prefilters[type] | | (match = Prefilters[type] (match)))) {//match[0] removes the match array and assigns it to matchedmatched = Match.shift ();//presses the match result into the tokens array Tokens.push ({value:matched,type: Type,matches:match});//Assign the string after the match result to Sofar, continue parsing sofar = Sofar.slice (Matched.length);}} */* If matched==false, * This cycle does not have a valid selector (including the relationship and ID, class and other type selectors) * Therefore, parsing to the current position left behind Sofar is an illegal selector string * Jump out while the Loop body */if (! matched) {break;}} Return the length of the invalid excess//if we ' re just parsing//Otherwise, throw an error or return tokens/* * if not on initial The selector string is parsed (!parseonly==true), * The Sofar.length is returned, and the SOF at this timeAr.length represents the final position of a continuous, valid selector, * Subsequent articles will be illustrated with an instance * if the initial selector string is parsed, see if Sofar has characters, * If so, execute Sizzle.error (selector) throws an exception; If not, execute Tokencache (selector, groups). Slice (0) presses the result into the cache and returns a copy of the result. */return parseonly? SoFar.length:soFar? Sizzle.error (selector)://Cache the Tokenstokencache (selector, groups). Slice (0);}
jquery Selector code detailed (a)--sizzle method
jquery Selector code in detail (ii)--select method
jquery Selector code in detail (iii)--tokenize method