JQuery selector source code (8): addCombinator function,

Source: Internet
Author: User

JQuery selector source code (8): addCombinator function,

Function addCombinator (matcher, combinator, base)

1. Source Code
Copy codeThe Code is 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. Functions

The execution function that generates the relationship selector.

3. Parameters

Matcher: a continuous array of filter selector matching functions before the positional relationship. This function is used to match nodes obtained through the positional relationship to meet the selector requirements. In actual execution, this function may be an elementMatcher (matchers) generated before the relational selector ). Example: div. map> span. When Sizzle is compiled, the div. the map compilation function calls the addCombinator function as the first parameter to check whether the obtained span parent node meets div. map conditions.

Combinator -- the relationship selector corresponds to the value in Expr. relative. The values of various relationship selectors in Expr. relative are as follows. Use the first attribute of this parameter to determine whether the returned function only checks the function of the adjacent object or traverses all possible functions of the object. Run the following code: elem = elem [dir] to obtain the node with the specified positional relationship, where dir is equal to combinator. dir.
Copy codeThe Code is as follows:
Expr. relative :{
"> ":{
Dir: "parentNode ",
First: true
},
"":{
Dir: "parentNode"
},
"+ ":{
Dir: "previussibling ",
First: true
},
"~ ":{
Dir: "previussibling"
}
}

Base -- this parameter is used with combinator. dir to determine the value of the variable checkNonElement. The Code is as follows. This value is literally considered as a non-DOM element for the current check, that is, when elem. nodeType! If the value is true, the matching function is executed. Otherwise, the loop is ended.

4. Return Functions

4.1 If the link selector is> or +, the following function is returned:
Copy codeThe Code is as follows:
Function (elem, context, xml ){
While (elem = elem [dir]) {
If (elem. nodeType = 1 | checkNonElements ){
Return matcher (elem, context, xml );
}
}
}

4.1.1 Functions
If you check the element type node (checkNonElements = false), iteration gets the first element type node (elem. nodeType = 1). Execute the matching function to check whether the node meets the requirements. If yes, return true; otherwise, return false;

If you check all types of nodes (I .e. checkNonElements = true), obtain the adjacent node of the specified location relationship of elem, execute the matching function, and check whether the node meets the requirements. If yes, true is returned, otherwise, false is returned;
Some may ask, isn't it a close relationship? Why does iterative retrieval occur in the code? This is because some browsers regard line breaks between node texts as textnodes. Therefore, during processing, skip these nodes until the next element node.
4.1.2 Parameters
Elem-Single Node element to be checked.

Context -- the context node that executes the entire selector string matching. It is useless in most cases.

Xml: whether the current search object is an HTML or an XML document. If it is an HTML document, the xml parameter is false.

4.2 if the link selector is ~ Or space, the following function is returned:
Copy codeThe Code is 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 Functions

If the XML document is checked, the process is the same as that of the 4.1 Return function. For details, see the code in parentheses in if (XML) {...} in the above Code.

If it is an HTML document, the current element is matched based on the matcher. If the matching succeeds, true is returned; otherwise, false is returned.

4.2.2 Parameters
Elem-Single Node element to be checked.

Context -- the context node that executes the entire selector string matching. It is useless in most cases.

Xml: whether the current search object is an HTML or an XML document. If it is an HTML document, the xml parameter is false.

4.2.3 Code Description

Internal Variable

Dirkey: The key used to cache node detection results. During an execution, if a node is checked, the detection result (true or false) is recorded in the dirkey attribute (the value of the attribute name dirkey) of the node ), during this execution, the node does not need to be detected again. Cache is required because multiple nodes have the same parent node or sibling node. Using the cache can reduce the number of detection times and improve performance.

Dirruns-a pseudo-random number is generated every time pre-compiled code is run through matcherFromGroupMatchers to differentiate different execution processes.
DoneName -- each time the addCombinator function is executed, the done variable will add 1 to differentiate the generated location relationship matching functions.

Cachedruns -- used to record the First DOM element of this match. For example, if div. map> span has three elements that match the span selector, then when the> matching function is executed for each element, the values of cachedruns are 0, 1, and 2 in sequence. The role of cachedruns can be directly understood by code as: in an execution process, when elementMatchers is used to match the same element, you can obtain unmatched results directly, but I don't know under which circumstances this will happen. If someone encounters this, please let us know. Thank you!

Code explanation
Copy codeThe Code is as follows:
While (elem = elem [dir]) {
If (elem. nodeType = 1 | checkNonElements ){
// If the expando attribute of the elem node does not exist, an empty object is assigned and the outerCache is also assigned.
// 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 is equal to the current dirkey,
* This indicates that the current position selector has detected this node during this execution. The if statement is executed and the result is obtained directly from the cache.
* If outCache [dir] does not exist, or the first element is not equal to the current dirkey,
* This indicates that the current position selector has not detected this node during this execution. It executes the statements in else, matches the node, and caches the results.
*/
If (cache = outerCache [dir])
& Cache [0] === dirkey ){
// If the detection result in the cache is equal to the value of true or cachedruns, the detection result is returned (all values other than true are false ),
// Otherwise, the node that matches the previous location is retrieved cyclically.
If (data = cache [1]) = true
| Data === cachedruns ){
Return data = true;
}
} Else {
// Assign the array [dirkey] To outerCache [dir] and cache
Cache = outerCache [dir] = [dirkey];
// Assign true to cache [1]. Otherwise, assign the value of cachedruns to cache [1].
Cache [1] = matcher (elem, context, xml)
| Cachedruns;
// If the matching result is true, true is returned. Otherwise, the previous matching node is obtained cyclically.
If (cache [1] === true ){
Return true;
}
}
}
}

Related Article

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.