Implementation Code for finding recent common ancestor elements in js

Source: Internet
Author: User

First, let's look at the concept. First, DOM is a tree, and its root node is Document, which can be roughly used to represent:

The so-called "Recent co-ancestor element" refers to the element that gives a series of elements to find out the largest depth in the tree, but is also the element of the ancestor element of all these elements.

For example, the results of I and G are C, G, and H. The results of D and E are html, and the results of C and B are html.

Test driver
For the logic-biased question, the function is not fully grasped. Therefore, we should first construct the test life and strive to let the function pass the test.

This time, the structure is used as the DOM structure. A indicates the body, B indicates the head, and other nodes use the div element. At the same time, the above content is used as the input and output of the test, first construct the test:Copy codeThe Code is as follows: function test (){
Var result;
Result = find ('I', 'G ');
Result. id! = 'C' & alert ('fail (I, g )');
Result = find ('G', 'H ');
Result. id! = 'A' & alert ('fail (g, h )');
Result = find ('D', 'E ');
Result. nodeName. toLowerCase ()! = 'Html' & alert ('fail (d, e )');
Result = find ('C', 'B ');
Result. nodeName. toLowerCase ()! = 'Html' & alert ('fail (c, B )');
}

Basic logic
This logic is roughly like this:

1. For each given element, traverse from the parent element to the document in sequence.
2. Each element passing through the traversal process is saved to an ordered map, with the element as the key and the number of traversal times as the value.
2. Finally, traverse the map to find the same item with the first value as the number of given elements, that is, the first element that is traversed by all elements, that is, the recent ancestor element.
Details
In the actual process, it is important to build a map. Two problems are involved:

1. map cannot directly use elements as keys and must be converted to appropriate primitive types (such as number, string, and Regex ).
2. chrome will automatically sort the keys in the object, so try to avoid using the number type as the key.

For the first question, you must bind an appropriate field to the element to act as a unique identifier. Fortunately, HTML5 provides the data-* attribute, which greatly improves the metadata carrying capability of DOM and can boldly add desired attributes.

The second problem is not difficult in itself. The generated identifier can be avoided by adding an underscore or converting String. fromCharCode into a character.
Implementation Code
The Code is a little long, mainly because I prefer the JAVA-based style. Every statement is clearly defined in every branch and does not like to use & or | to process condition branches, so there are many rows with only one braces and so on. In fact, the really effective code is still streamlined. I am too lazy to install plug-ins like toggle and don't want to see the scroll bar. I just threw them here.Copy codeThe Code is as follows: function find (){
Var length = arguments. length,
I = 0,
Node, // current node
Parent, // parent node
Counter = 0,
Uuid, // unique identifier for the DOM
Hash = {}; // map of the final result

// Traverse each element to the document
// This double loop is inevitable.
For (; I <length; I ++ ){
// Obtain the node
Node = arguments [I];
If (typeof node = 'string '){
Node = document. getElementById (node );
}
// Traverse up
While (parent = node. parentElement | node. parentNode ){
// Stop at document. Otherwise, it is an endless loop.
If (parent. nodeType = 9 ){
Break;
}
// Obtain or add an identifier
Uuid = parent. getAttribute ('data-find ');
If (! Uuid ){
Uuid = '_' + (++ counter); // chrome does not reorder hash.
Parent. setAttribute ('data-find ', uuid );
}
// Increase the count
If (hash [uuid]) {
Hash [uuid]. count ++;
}
Else {
Hash [uuid] = {node: parent, count: 1 };
}
Node = parent;
}
}
// The hash contains only the parent nodes that traverse each node up. It should not be large.
// Therefore, this loop is faster.
For (I in hash ){
If (hash [I]. count = length ){
Return hash [I]. node;
}
}
};

Comments
The test is okay, but it is hard to say whether the test cases are perfect. I hope the netizens can help me find out the problem. I am not confident about the logic type. It's okay to say 100%.
For getting the parent element, it is customary to be compatible with IE and write it as parentElement | parentNode. This is because of a BUG in IE. When an element has just been created but has not entered the DOM, parentNode does not exist. However, this function ensures that the node is in the DOM tree. In fact, parentElement is unnecessary. So sometimes habitual code compatibility is not necessarily a good thing. The code that best suits the current environment is good code.
Although the double loop is inevitable, there is still a way to do less in a specific situation, for example, if we find that an element is no longer a common ancestor of all elements, we should not increase the count value.
Is there a way to save the final for... in loop? In the above two repeated loops, is there a way to keep the most suitable node in real time through a variable?

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.