JQuery3.1.1 Source code Interpretation (c) "Sizzle selector"

Source: Internet
Author: User
Tags closure regular expression tagname
Sizzle Selector

Sizzle, originally used as a DOM selector in JQuery, was later separated by John Resig and became a separate project that can be directly imported into the project for use.

We used JQuery as a selector, select some #id or. class, use document.getElementById or document.getelemensbyclassname to quickly lock the location of the DOM, and then return to JQuery as an object. But sometimes there are some more complicated choices. Div Div.hot>span This kind of affirmation with the above function is not possible, the first consideration is the Element.queryselectorall () function, but this function has a serious compatibility problem MDN Queryselectorall. Sizzle will come in handy at this time.

The init function is described in white and does not introduce the Find function, which is essentially the performance of the Sizzle function in JQuery. This function has one of two forms of existence in JQuery, that is, the prototype and the attribute, and first look at the JQuery.fn.find:

JQuery.fn.find = function (selector) {
  var i, ret, len = this.length, self
    = this;
  I don't know what it is.
  if (typeof selector!== "string") {
    //Fn.pushstack and Jquery.merge are similar, but return a jquery object, and
    //JQ  Uery has a prevobject attribute pointing to itself
    return This.pushstack (JQuery (selector). Filter (function () {for
      (i = 0; i < len; i++) {
        //Jquery.contains (A, B) determine if a is a parent of B
        if (Jquery.contains (Self[i], this)) {
            return true;
        }
      }
    }));
  }

  ret = This.pushstack ([]);

  for (i = 0; i < len; i++) {
    //referenced here to Jquery.find function
    jquery.find (selector, self[i], ret);
  }
  Uniquesort function
  return len > 1? jquery.uniquesort (ret): ret;
}

The usage of JQuery.fn.find is generally in the $ ('. Test '). FIND ("span"), so this is the point of the $ ('. Test '), which is understood by the following things.

Then there is the Jquery.find function, which is the key part of this chapter. First look at a regular expression:

var rquickexpr =/^ (?: # ([\w-]+) | ( \w+) |\. ([\w-]+)) $/;
Rquickexpr.exec (' #id ')//["#id", "id", Undefined, undefined]
rquickexpr.exec (' div ')//["div", Undefined, "div", Undefined]
rquickexpr.exec ('. Test ')//[". Test", Undefined, undefined, "test"]
rquickexpr.exec (' div p ')// Null

You may wonder, the name of Rquickexpr has appeared once. In fact, Sizzle is a closure, and this rquickexpr variable is within the Sizzle closure, without affecting the overall jQuery. This regular function is mainly used to distinguish between the tag, ID and class, and from the returned array also has a certain law, you can use this rule to determine which selector specific.

Jquery.find = Sizzle; function Sizzle (selector, context, results, seed) {var m, I, Elem, nid, Match, groups, newselector, Newcontext = Contex T && context.ownerdocument,//NodeType defaults to 9, since context defaults to document NodeType = Context ?

  Context.nodetype:9; Results = Results | |

  []; Return early from calls with invalid selector or context if (typeof selector!== "string" | |!selector | | nodeType! =
  = 1 && nodeType!== 9 && nodeType!== one) {return results; }//Try to shortcut find operations (as opposed to filters) in HTML documents if (!seed) {if (context? conte xt.ownerdocument | | Context:preferreddoc)!== document) {//Setdocument function is actually used to set the context to document, considering the compatibility of the browser setdocument (CO
    ntext); } context = Context | |
    Document True if (documentishtml) {//Match is the regular array if (NodeType!== && (match = Rquickexpr.exec (selector))) {//SelectoR is the case of the ID if ((M = match[1])) {//Document context if (nodeType = = = 9) {if (E
                  Lem = Context.getelementbyid (m)) {if (elem.id = = = m) {Results.push (elem);
              return results;
            }} else {return results; }//Non-document case} else {if (Newcontext && (elem = Newcontext.getelementbyid
                (m)) && contains (context, elem) && elem.id = = = m) {Results.push (elem);
            return results; 
            }}//selector is tagName condition} else if (Match[2]) {//Push:var push = Arr.push here
            Push.apply (results, Context.getelementsbytagname (selector));

        return results; Selector is the class condition} else if ((M = match[3]) && support.getelementsbyclassname && Context.gete

      Lementsbyclassname) {      Push.apply (Results, Context.getelementsbyclassname (m));
        return results; }}//If the browser supports Queryselectorall if (SUPPORT.QSA &&!compilercache[selector + ""] && (! RBUGGYQSA | |
          !rbuggyqsa.test (selector)) {if (NodeType!== 1) {newcontext = context;

          Newselector = selector;  QSA looks outside Element context, which is isn't what we want//Support:ie <=8, or to consider compatibility} else if (Context.nodeName.toLowerCase ()!== "Object")
            {//Capture the context ID, setting it first if necessary if (nid = Context.getattribute ("ID")) {
          Nid = Nid.replace (Rcssescape, Fcssescape);
          } else {Context.setattribute ("id", (nid = expando));
          }//Sizzle part of lexical analysis groups = tokenize (selector);
          i = groups.length;
         while (i--) {groups[i] = "#" + Nid + "" + toselector (Groups[i]); } Newselector = Groups.join (","); Expand context for sibling selectors newcontext = Rsibling.test (selector) && TestContext (context.pare Ntnode) | |
        Context
            } if (Newselector) {try {push.apply (results, Newcontext.queryselectorall (newselector));
          return results;
            } catch (Qsaerror) {} finally {if (nid = = = expando) {context.removeattribute ("id"); }}}}}}//All others,select function and Tokenize function later on return select (selector.replace
(RTrim, "$"), context, results, seed); }

The whole analysis process looks very long due to various factors, including efficiency and browser compatibility, but the logic is not difficult: first determine whether the selector is a non-string, and then rquickexpr the selector to match, get the array in turn consider the ID, TagName and class situation, these are very simple, are a single choice, generally with the browser's own function getelement can be solved. Encounter a bit more complex, such as Div Div.show P, first consider whether the Queryselectorall function is supported, and then consider the browser-compatible ie<8. If not, give to the Select function (Next chapter). Advantages of Sizzle

Sizzle uses a right-to-left selection method, which is more efficient.

When the browser is working with HTML, Mr. Tess a DOM tree, parses the CSS, and then creates a render tree with more CSS and DOM. The render tree is used for rendering, not one by one correspondence, such as Display:none's DOM will not appear in the render tree.

If a left-to-right match, Div Div.show P, find the div node, find the div from the 1 sub-node and the DOM of class show, then go back to the previous step to find the P element from the 2 child node, and then go back to the previous step

If one step is not found, backtrack upward until all the div is traversed, which is inefficient.

If the right-to-left way, the first match to all the P-node, the results of the 1 attention to judge, if its parent node in order to appear div.show and Div, then retain, otherwise discarded

Because child nodes can have several, and the parent node has only one, the right-to-left approach is highly efficient. derived functions JQuery.fn.pushStack

JQuery.fn.pushStack is a function similar to Jquery.merge, which takes a parameter, merges the parameter (array) into a JQuery object and returns the source code as follows:

JQuery.fn.pushStack = function (elems) {

  //Build a new JQuery matched element set
  var ret = Jquery.merge (This.con Structor (), elems);

  ADD the old object onto the stack (as a reference)
  ret.prevobject = this;

  Return the newly-formed element set
  return ret;
}
Jquery.contains

This function is to determine whether the DOM is a parent-child relationship, the source code is as follows:

Jquery.contains = function (context, elem) {
  //For compatibility, set the value of the context
  if ((Context.ownerdocument | | context)!== DO cument) {
    setdocument (context);
  }
  return contains (context, elem);
}

Contains is an intrinsic function that determines whether dom_a is Dom_b
var contains =  function (A, b) {
  var adown = A.nodetype = = 9? a.docum Entelement:a,
  bup = b && b.parentnode;
  return a = = = Bup | | !! (bup && Bup.nodetype = = = 1 && (
  adown.contains) adown.contains (BUP): A.comparedocumentposition &am p;& a.comparedocumentposition (BUP) &);
}
Jquery.uniquesort

The de-emphasis function of jQuery, but this de-emphasis function handles the array of DOM elements and cannot handle strings or arrays of numbers to see what is Special:

Jquery.uniquesort = function (results) {
  var elem, duplicates = [],
    j = 0,
    i = 0;

  Hasduplicate is a flag that determines whether there is the same element, global
  hasduplicate =!support.detectduplicates;
  Sortinput =!support.sortstable && results.slice (0);
  Results.sort (SortOrder);

  if (hasduplicate) {while
    ((Elem = results[i++])) {
      if (elem = = = Results[i]) {
          j = duplicates.push (i);
      }
    } while
    (j--) {
      //splice is used to remove duplicate elements
      results.splice (Duplicates[j], 1);
    }
  }

  Clear input after sorting to release objects
  //See https://github.com/jquery/sizzle/pull/225
  sortinput = nu ll;

  return results;
}

The SortOrder function is as follows, you need to put two functions together to understand to better understand OH:

var sortOrder = function (A, B) {//= has the same element, set flag to True if (a = = b) {hasduplicate = true;
  return 0; }//Sort on method existence if only one input has comparedocumentposition var compare =!a.comparedocumentposition
  -!b.comparedocumentposition;
  if (Compare) {return compare; }//Calculate position if both inputs belong to the same document compare = (A.ownerdocument | | a) = = = (b.ownerdocum ent | | b)?

  A.comparedocumentposition (b)://Otherwise We know they are disconnected 1; Disconnected nodes if (Compare & 1 | | (!support.sortdetached && b.comparedocumentposition (a) = = = Compare))  {//Choose the first element is related to our preferred document if (a = = Document | | a.ownerdocument = = =
    Preferreddoc && contains (Preferreddoc, a)) {return-1;
    if (b = = = Document | | b.ownerdocument = = = Preferreddoc && contains (Preferreddoc, B)) {return 1; }//Maintain OriGinal order return sortinput?
  (IndexOf (Sortinput, a)-IndexOf (sortinput, b)): 0; } return compare & 4?
-1:1; }
Summary

It can be said that today first to Sizzle open head, any heavy and long way. The tokens and select functions in Sizzle are accepted below. Reference

JQuery 2.0.3 Source Analysis Sizzle engine-lexical parsing

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.