JQuery selector source code (1): Sizzle method, jquerysizzle
After in-depth analysis of jQuery's Sizzle methods (also referring to some online materials), I will share the results with you. I will use the serialization method to explain in detail some methods used by Sizzle. Each article introduces a method.
If you need to reprint the data, please specify the source. Thank you.
/** The Sizzle method is the main entry to the Sizzle selector package. jQuery's find method is to call this method to obtain matching nodes * This method mainly completes the following tasks: * 1. For a single selector, if it is one of the three types: ID, Tag, and Class, the system directly obtains and returns the result * 2. For browsers that support the querySelectorAll method, run querySelectorAll to obtain and return the matched DOM element * 3. Call the select method to obtain and return the matched DOM element *** @ param selector string * @ param context execute the initial context of the match (that is, the DOM element set ). If the context value is not assigned, the document is used. * @ Param results: the final result of the matched part. If results is not assigned a value, an empty array is assigned. * @ Param seed initial set */function Sizzle (selector, context, results, seed) {var match, elem, m, nodeType, // QSA varsi, groups, old, nid, newContext, newSelector;/** preferredDoc = optional values Doc ument ** setDocument method to complete some initialization work */if (context? Context. ownerDocument | context: preferredDoc )! = Document) {setDocument (context);} context = context | document; results = results | [];/** if selector is not a valid string type data, then results */if (! Selector | typeof selector! = "String") {return results;}/** if context is neither document (nodeType = 9) nor element (nodeType = 1 ), then return the empty Set */if (nodeType = context. nodeType )! = 1 & nodeType! = 9) {return [];} // if the HTML document is currently filtered and seed is not set, run the if (documentIsHTML &&! Seed) {/** if the selector is a single selector and is one of the three types: ID, Tag, and Class, the system directly obtains and returns the result ** rquickExpr =/^ (?: # ([\ W-] +) | (\ w +) | \. ([\ w-] + )) $/* the three paragraphs in the brackets of the above regular expression are used to determine whether the single selector is ID, TAG, and CLASS respectively. * The above regular expression has three subexpressions in the outermost parentheses (namely, three parentheses ), * represents the values of ID, Tag, and Class selector respectively. In the following code, match [1], match [2], match [3] */if (match = rquickExpr.exe c (selector) {// Speed-up: sizzle ("# ID") // process the ID type selector, for example, # IDif (m = match [1]) {// if the current context is a document, then execute the if statement body if (nodeType = 9) {elem = context. getElementById (m); // Check parentNode to catch When Blackberry 4.6 // returns // nodes that are no longer in the document # 6963if (elem & elem. parentNode) {// Handle the case where IE, Opera, and Webkit // return items // by name instead of ID/** some earlier browsers treat name as ID, * return incorrect results, so we need to compare and return the node ID attribute again */if (elem. id = m) {results. push (elem); return results ;}} else {// Context is not a document/** contains (context, elem) To check whether the obtained elem is the sub-object of the current context object */if (context. ownerDocument & (elem = context. ownerDocument. getElementById (m) & contains (context, elem) & elem. id = m) {results. push (elem); return results ;}// Speed-up: Sizzle ("TAG") // process the Tag type selector, for example: SPAN} else if (match [2]) {push. apply (results, context. getElementsByTagName (selector); return results; // Speed-up: Sizzle (". CLASS ")/** process class type selectors, such :. class * the following condition judgments are: * M = match [3]: Valid class type selector * support. getElementsByClassName the div of this selector supports getElementsByClassName * context. getElementsByClassName the current context node has the getElementsByClassName method **/} else if (m = match [3]) & support. getElementsByClassName & context. getElementsByClassName) {push. apply (results, context. getElementsByClassName (m); return results ;}// QSA path/** if the browser supports the querySelectorAll method and the selector complies with the querySelectorAll call standard, Then execute the if statement body * The check here is only a simple match * When Sizzle is called for the first time, rbuggyQSA is blank ** if statement body assigns a value to and restores the id of the current context object, is a BUG used to fix querySelectorAll * this BUG will return the current node (context) as a result in some cases. * The specific method is to add an attribute selector before the existing selector: [id = XXX], * XXX is the id of the context. If the context itself does not set an id, the default value is expando. */If (support. qsa &&(! RbuggyQSA |! RbuggyQSA. test (selector) {nid = old = expando; newContext = context; // If context is document, newSelector is taken from selector, otherwise, falsenewSelector = nodeType = 9 & selector; // qSA works strangely on Element-rooted queries // We can work around this by specifying an extra ID on the // root // and working up from there (Thanks to Andrew Dupont // the technique) // IE 8 doesn' t work on object elementsif (nodeType === 1 & context. nodeName. toLowerCase ()! = "Object") {groups = tokenize (selector); if (old = context. getAttribute ("id") {/** rescape =/'| \/g, * Here, a backslash (* old) is added before single quotes, vertical bars, and backslashes in old. $ & in replace (rescape, "\\$ &") code indicates a match */nid = old. replace (rescape, "\\$ &");} else {context. setAttribute ("id", nid) ;}nid = "[id = '" + nid + "']"; // recombine the new selector I = groups. length; while (I --) {groups [I] = nid + toSelector (groups [I]);}/** rsibling = new RegExp (whitesp Ace + "* [++] ") * Rsibling is used to determine whether the selector has a sibling relationship * if it contains ~ The parent node of the context as the current node */newContext = rsibling. test (selector) & context. parentNode | context; newSelector = groups. join (",");} if (newSelector) {/** use try... catch, * because some selectors supported by jquery are not supported by querySelectorAll. * when these selectors are used, querySelectorAll reports an invalid selector. * jquery must implement them. */Try {// merge the results obtained by querySelectorAll into results, and then return resulstspush. apply (results, newContext. querySelectorAll (newSelector); return results;} catch (qsaError) {} finally {if (! Old) {context. removeAttribute ("id") ;}}}// All others // In addition to the preceding shortcut and querySelectorAll method, all others need to call select to obtain the result/** rtrim = new RegExp ("^" + whitespace + "+ | ((?: ^ | [^ \\\\]) (? :\\\\.) *) "* + Whitespace +" + $ "," g "), * whitespace =" [\ x20 \ t \ r \ n \ f] "; * The rtrim regular expression is used to remove the blank spaces on both sides of the selector, blank characters are defined by the whitespace variable * rtrim effect and new RegExp ("^" + whitespace + "+ |" + whitespace + "+ $", "g ") similar to */return select (selector. replace (rtrim, "$1"), context, results, seed );}
Dear friends, if you think it's a good job, help me with it and give me some motivation. Thank you!