Home > Article > Web Front-end > jQuery selector source code interpretation (8): addCombinator function_jquery
function addCombinator(matcher, combinator, base)
1、源码
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、功能
生成关系选择器的执行函数。
3、参数
matcher——位置关系前连续的过滤选择器匹配函数数组,该函数用于匹配通过位置关系获得的节点是否符合选择器要求。在实际执行过程中,该函数可能是关系选择器前已生成的elementMatcher(matchers)。例如:div.map>span,在Sizzle编译遇到>时,会将div.map的编译函数作为第一个参数调用addCombinator函数,用以检查获取的span父节点是否满足div.map这两个条件。
combinator——关系选择器对应Expr.relative中的值,Expr.relative中各种关系选择器的值如下。使用该参数的first属性来确定返回的是仅检查紧邻对象的函数还是遍历所有可能对象的函数。将通过如下代码:elem = elem[dir],获取指定位置关系的节点,其中dir等于combinator.dir。
base - This parameter, together with combinator.dir, determines the value of the variable checkNonElement. The code is as follows. This value is literally understood to mean that the current check is a non-DOM element, that is, when elem.nodeType!=1, if the value is true, the matching function will be executed, otherwise the loop will end.
4. Return function
4.1 If the relationship selector is > or , the following function is returned:
4.1.1 Function
If the element type node is checked (i.e. checkNonElements==false), iteratively obtain the first element type node of the elem specified position relationship (elem.nodeType == 1), execute the matching function, check whether the node meets the requirements, and return true if it meets the requirements. , otherwise return false;
If all types of nodes are checked (i.e. checkNonElements==true), get the adjacent nodes with the specified position relationship of elem, execute the matching function, check whether the node meets the requirements, return true if it meets the requirements, otherwise return false;
Some people may ask, isn't it said that it is a close neighbor relationship? So why does the process of iterative acquisition appear in the code? This is because some browsers will regard the line breaks between node texts as TextNode, so during processing, these nodes need to be skipped until the next element node.
4.1.2 Parameters
elem – the single node element to be checked.
context - the context node that performs the entire selector string matching, most of the time it is useless.
xml——Is the current search object an HTML or XML document? If it is HTML, the xml parameter is false.
4.2 If the relationship selector is ~ or space, the following function will be returned:
// 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 process is the same as the return function in 4.1. See the code within the curly brackets in if (XML) { ... } in the above code.
If it is an HTML document, match the current element according to the matcher. If the match is successful, return true; otherwise, return false.
4.2.2 Parameters
elem – the single node element to be checked.
context - the context node that performs the entire selector string matching, most of the time it is useless.
xml——Is the current search object an HTML or XML document? If it is HTML, the xml parameter is false.
4.2.3 Code Description
Internal variables
dirkey - the key used to cache node detection results. During an execution, if a node is checked, the detection result (true or false) will be recorded in the node's dirkey attribute (the attribute name is the value of dirkey). Then during this execution, if it is encountered again When reaching this node, there is no need to detect it again. The reason why caching is needed is because multiple nodes will have the same parent node or sibling node. Using caching can reduce the number of detections and improve performance.
dirruns - Each time the precompiled code organized by matcherFromGroupMatchers is executed, a pseudo-random number will be generated to distinguish different execution processes.
doneName——Every time the addCombinator function is executed, the done variable will be incremented by 1 to distinguish the different generated position relationship matching functions.
cachedruns - used to record which DOM element this match is. For example: div.map>span, there are 3 elements that match the span selector, then when the > matching function is executed for each element, the cachedruns are 0, 1, and 2 in order. According to the code, the role of cachedruns can be directly understood as during an execution process, when using elementMatchers for the same element for matching, when the same element is encountered again, the unmatched result can be obtained directly from This is what happens. If anyone encounters it, please let me know, thank you!
Code explanation