JQuery Sizzle entry [Source Code Analysis]
Var Sizzle = function (selector, context, results, seed) {// The default context is document. You can manually specify results = results | []; context = context | document; var origContext = context; // judge if (context. nodeType! = 1 & context. nodeType! = 9) {return [];} // whether the expression is a string if (! Selector | typeof selector! = "String") {return results;} // set: Seed set // checkSet: Copy of seed set // extra: Save the remaining parallel expression, note: The parallel expression // ret is returned. The data type is json, which contains the set and expr attributes. set is the seed set, and expr is the remaining block expression. // cur: the link character of the block expression is as follows: +> ~ If not, the default value is space "" // pop: The last variable of the pop-up array // parts: stores the currently split block expression array var m, set, checkSet, extra, ret, cur, pop, I, prune = true, contextXML = Sizzle. isXML (context), parts = [], soFar = selector; // Reset the position of the chunker regexp (start from head) // you can specify a parallel expression, the end is now. Save the remaining parallel expressions in extra. // For example, # info. p, div. red> ado export chunker.exe c (""); m = chunker.exe c (soFar); if (m) {soFar = m [3]; parts. push (m [1]);/ /Based on the preceding chunker regular expression, if there is a parallel expression, the value of m [2] After exec is "," if (m [2]) {// m [3] is the remaining parallel expression extra = m [3]; break ;}}while (m); // It will be cut as follows: // parts ["# info ",". p "], extra: div. red> a // determine whether there is a location pseudo class origPOS, such as: frist,: last, etc. if there is a location pseudo class, search from left to right for if (parts. length> 1 & origPOS.exe c (selector) {if (parts. length = 2 & Expr. relative [parts [0]) {set = posProcess (parts [0] + parts [1], context, seed);} else {set = Expr. Relative [parts [0]? [Context]: Sizzle (parts. shift (), context); while (parts. length) {selector = parts. shift (); if (Expr. relative [selector]) {selector + = parts. shift () ;}set = posProcess (selector, set, seed );}}} else {// Take a shortcut cut and set the context if the root selector is an ID // (but not if it'll be faster if the inner selector is an ID) // here we mainly modify the context. If the expression starts with the ID type and the last expression is not the ID type, // all the queries, use sizzle. se Lector. find has only the last node, and other nodes can adopt the relationship to determine // The reason why only the first node is id can modify the context, and the last node cannot be ID, because getElementById only exists in the document // This method does not exist in the element. If the last element is ID, an error is reported. // then, the context is changed to the node where the ID is located, to improve efficiency // For example: $ ("# info. p "); then the automatic modification is as follows: $ (". p ", $ (" # info "); if (! Seed & parts. length> 1 & context. nodeType = 9 &&! ContextXML & Expr. match. ID. test (parts [0]) &! Expr. match. ID. test (parts [parts. length-1]) {// call the find method to query the first element in parts and return a temporary result. // if the preceding # info. p will be directly queried # info, and the returned result ret = Sizzle. find (parts. shift (), context, contextXML); // modify contextcontext = ret. expr? Sizzle. filter (ret. expr, ret. set) [0]: ret. set [0];} if (context) {// because the search is performed from right to left, obtain the last element of the array and call parts. pop (); // call the find method to query ret = seed? {Expr: parts. pop (), set: makeArray (seed)}: Sizzle. find (parts. pop (), parts. length = 1 & (parts [0] = "~ "| Parts [0] ===" + ") & context. parentNode? Context. parentNode: context, contextXML); // filter the result set = ret. expr? Sizzle. filter (ret. expr, ret. set): ret. set; if (parts. length> 0) {checkSet = makeArray (set);} else {prune = false;} // continue to the left part of the last element in the block expression. If yes, call link regular expression judgment // such as 1. div. red> p, so p has already been queried. Now the element in parts is ['div. red', '>']; // 2. div. red p, and p has been queried above. Now the element in parts is ['div. red']; while (parts. length) {// retrieve the last element, that is, '>'. If this is the second case, it is 'div. red 'cur = parts. pop (); pop = cur; // whether there is a link symbol. if it is a space, if (! Expr. relative [cur]) {// query whether the cur type exists. For example, in the second case, assign the cur value to "", and then the pop value is div. redcur = "";} else {// retrieve the upper-level element. In the first case, you need to retrieve the last element, which is div. redpop = parts. pop () ;}// if pop is empty, then the default value is entif (pop = null) {pop = context ;}// call the link regular expression judgment, pop is the expression of the element on the left, checkSet is the element to be filtered, and cur is the relational character. // one point to emphasize here is that some people will find that it is called directly and there is no return value, // how can the filtered results be returned? // Here, the javascript function is used to pass values to the array. Modify the checkSet value in the called function. // use the checkSet value later, will also change Expr. relative [cur] (checkSet, pop, contextXML) ;}} else {checkSet = parts = [] ;}} if (! CheckSet) {checkSet = set;} if (! CheckSet) {Sizzle. error (cur | selector);} if (toString. call (checkSet) = "[object Array]") {if (! Prune) {results. push. apply (results, checkSet);} else if (context & context. nodeType = 1) {for (I = 0; checkSet [I]! = Null; I ++) {if (checkSet [I] & (checkSet [I] = true | checkSet [I]. nodeType = 1 & Sizzle. contains (context, checkSet [I]) {results. push (set [I]) ;}} else {for (I = 0; checkSet [I]! = Null; I ++) {if (checkSet [I] & checkSet [I]. nodeType = 1) {results. push (set [I]) ;}}} else {makeArray (checkSet, results);} if (extra) {// a parallel expression exists and Sizzle (extra, origContext, results, seed); // sort the results to remove duplicates and merge the Sizzle. uniqueSort (results);} return results ;};