jquery Selector Source code interpretation (eight): Addcombinator function _jquery

Source: Internet
Author: User

function Addcombinator (Matcher, Combinator, Base)

1, source code

Copy Code code as follows:

function Addcombinator (Matcher, Combinator, base) {
var dir = combinator.dir, checknonelements = base
&& dir = = = "ParentNode", donename = done++;

Return Combinator.first?
Check against closest ancestor/preceding element
function (elem, context, XML) {
while ((Elem = Elem[dir])) {
if (Elem.nodetype = = 1 | | checknonelements) {
Return Matcher (Elem, context, XML);
}
}
} :

Check Against all ancestor/preceding elements
function (elem, context, XML) {
var data, Cache, Outercache, Dirkey = Dirruns + "" + donename;

We can ' t set arbitrary data on XML nodes, so they don ' t
Benefit from DIR caching
if (XML) {
while ((Elem = Elem[dir])) {
if (Elem.nodetype = = 1 | | checknonelements) {
if (Matcher (elem, Context, XML)) {
return true;
}
}
}
} else {
while ((Elem = Elem[dir])) {
if (Elem.nodetype = = 1 | | checknonelements) {
Outercache = Elem[expando] | | (Elem[expando] = {});
if (cache = Outercache[dir])
&& cache[0] = = Dirkey) {
if ((data = cache[1]) = = True
|| data = = Cachedruns) {
return data = = true;
}
} else {
Cache = Outercache[dir] = [Dirkey];
CACHE[1] = Matcher (elem, Context, XML)
|| Cachedruns;
if (cache[1] = = True) {
return true;
}
}
}
}
}
};
}

2, function

Builds the execution function of the relationship selector.

3. Parameter

matcher--a sequential array of filter selector matches before the position relationship, which is used to match whether a node obtained through a positional relationship meets the selector requirements. During actual execution, the function may be the Elementmatcher (matchers) that was generated before the relationship selector. For example: Div.map>span, when sizzle compilation encounters >, it calls the Div.map's compile function as the first parameter Addcombinator function to check whether the acquired span parent satisfies the DIV.MAP condition.

The combinator--relationship selector corresponds to the value in Expr.relative, and the values of the various relationship selectors in expr.relative are as follows. Use this parameter's top property to determine whether to return a function that checks only the immediate object or all possible objects. Gets the node for the specified location relationship, where Dir equals Combinator.dir, by using the following code: Elem = Elem[dir].

Copy Code code as follows:

Expr.relative: {
">": {
Dir: "ParentNode",
First:true
},
" " : {
Dir: "ParentNode"
},
"+" : {
Dir: "PreviousSibling",
First:true
},
"~" : {
Dir: "PreviousSibling"
}
}

base--This parameter, together with Combinator.dir, determines the value of the variable checknonelement, the code below. This value is literally interpreted as a non-dom element that is currently checked, that is, when elem.nodetype!=1, if the value is true, the matching function is executed, otherwise the loop ends.

4. Return function

4.1 If the relationship selector is > or +, the following function is returned:

Copy Code code as follows:

function (elem, context, XML) {
while ((Elem = Elem[dir])) {
if (Elem.nodetype = = 1 | | checknonelements) {
Return Matcher (Elem, context, XML);
}
}
}

4.1.1 function
If the element type node (that is, checknonelements==false) is checked, the iteration gets the first element type node (Elem.nodetype = 1) of the Elem specified position relationship, performs a matching function to check that the node meets the requirements, Returns False if the match returns true;

If you check all types of nodes (that is, checknonelements==true), get the immediate node of the Elem specified location relationship, perform a matching function, check that the node meets the requirements, and return False if the match returns true;
Some people may ask, is not to say the immediate relationship? Why does the code have an iterative process to get there? This is because individual browsers think of line breaks between the text of the nodes as Textnode, so in the process of processing, you need to skip these nodes until the next element node.
4.1.2 Parameters
elem--a single node element to be examined.

context--executes a context node that matches the entire selector string, most of the time without a purpose.

xml--whether the current search object is HTML or an XML document, and if HTML, the XML parameter is false.

4.2 If the relationship selector is ~ or a space, the following function is returned:

Copy Code code as follows:

Check Against all ancestor/preceding elements
function (elem, context, XML) {
var data, Cache, Outercache, Dirkey = Dirruns + "" + donename;

We can ' t set arbitrary data on XML nodes, so they don ' t
Benefit from DIR caching
if (XML) {
while ((Elem = Elem[dir])) {
if (Elem.nodetype = = 1 | | checknonelements) {
if (Matcher (elem, Context, XML)) {
return true;
}
}
}
} else {
while ((Elem = Elem[dir])) {
if (Elem.nodetype = = 1 | | checknonelements) {
Outercache = Elem[expando] | | (Elem[expando] = {});
if (cache = Outercache[dir])
&& cache[0] = = Dirkey) {
if ((data = cache[1]) = = True
|| data = = Cachedruns) {
return data = = true;
}
} else {
Cache = Outercache[dir] = [Dirkey];
CACHE[1] = Matcher (elem, Context, XML)
|| Cachedruns;
if (cache[1] = = True) {
return true;
}
}
}
}
}
};

4.2.1 function

If you are checking an XML document, the procedure is consistent with the 4.1 return function, as shown in the above code if (XML) {...} The code inside the curly braces.

If the HTML document matches the current element according to Matcher, returns true if the match succeeds, otherwise it returns false.

4.2.2 Parameters
elem--a single node element to be examined.

context--executes a context node that matches the entire selector string, most of the time without a purpose.

xml--whether the current search object is HTML or an XML document, and if HTML, the XML parameter is false.

4.2.3 Code Description

Internal variables

Keys for dirkey--cache node detection results. In the course of one execution, if a node is checked, the detection result (true or false) is recorded in the Dirkey property of the node (the value of the property name is Dirkey), then the node is not detected again when it is encountered again during this execution. Caching is required because multiple nodes can have the same parent node or sibling node, and caching reduces the number of detections and improves performance.

dirruns--produces a pseudo-random number each time it executes a precompiled code that is organized through matcherfromgroupmatchers to distinguish between different execution processes.
donename--each time the Addcombinator function is executed, the done variable is added 1 to distinguish between the different position-matching functions generated.

cachedruns--is used to record how many DOM elements this match is. For example: Div.map>span, where 3 elements conform to the span selector, Cachedruns 0, 1, 2 for each element when the > match function is executed. The role of Cachedruns can be directly understood in the code as an execution, when the same element is used to match the same elements, the same element can be directly retrieved from the results of the mismatch, but I can't think of a situation where this can happen. If someone encounters, please tell, thank you!

Code explanation

Copy Code code as follows:

while ((Elem = Elem[dir])) {
if (Elem.nodetype = = 1 | | checknonelements) {
If the expando property of the Elem node does not exist, it is given an empty object and the Outercache is given
If the expando attribute of the Elem node exists, the value is assigned to the Outercache
Outercache = Elem[expando] | | (Elem[expando] = {});
/*
* If OUTCACHE[DIR] has a value, and its first element equals the current Dirkey,
* indicates that the current location selector has detected the node during this execution, executes the statements within if, and obtains the result directly from the cache
* If OUTCACHE[DIR] does not exist, or the first element is not equal to the current Dirkey,
* Indicates that the current position selector has not detected the node during this execution, executes the statement within else, matches the node and puts the result in the cache
*/
if (cache = Outercache[dir])
&& cache[0] = = Dirkey) {
If the detected result in the cache is equal to TRUE or Cachedruns value, the test result is returned (not true to false).
Otherwise, continue looping to get the previous matching location relationship node to match
if ((data = cache[1]) = = True
|| data = = Cachedruns) {
return data = = true;
}
} else {
Assign an array [Dirkey] to Outercache[dir] and cache
Cache = Outercache[dir] = [Dirkey];
Will match successfully, give true cache[1], otherwise assign cachedruns value to cache[1]
CACHE[1] = Matcher (elem, Context, XML)
|| Cachedruns;
Returns true if the match result is true, otherwise it continues looping to get the previous matching position relationship node to match
if (cache[1] = = True) {
return true;
}
}
}
}

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.