1. Show the different ways of selecting an element from DOM
- The element can be selected using its tagname, id, attribute, value etc
document.getElementById("elementId"); // elementId is id of the element
document.querySelector(".my-class"); // element having a class 'my-class'
Notes
Above selectors are used to select a first matching element reference even if multiple matches be there
References
- https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector
- https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById
2. Show the ways to loop over the Nodelist obtained after querying for the elements
- The Nodelist can be obtained by queryng for multiple elements
- As list of elements are array like object (not pure JS array), all the array methods can’t be directly used
// Lets assume DOM elements are fetched in the variable domElements
for (let element of domElements) {
// perform operation on element
}
References
3. Design and Implement a Node Store, which supports DOM element as key
- Implement it without using inbuilt Map
- Can you do it in O(1) Time complexity?
class NodeStore {
constructor() {
this.store = {};
}
/**
* @param {Node} node
* @param {any} value
*/
set(node, value) {
node.__nodeIdentifier__ = Symbol();
this.store[node.__nodeIdentifier__] = value;
}
/**
* @param {Node} node
* @return {any}
*/
get(node) {
return this.store[node.__nodeIdentifier__];
}
/**
* @param {Node} node
* @return {Boolean}
*/
has(node) {
return !!this.store[node.__nodeIdentifier__];
}
}
References
4. Implement a function to find the closest ancestor with the provided selector (Element.closest() method)
- The closest() method traverses the Element and its parents (heading toward the document root) until it finds a node that matches the provided selector string. Will return itself or the matching ancestor. If no such element exists, it returns null.
Element.prototype.closest = function (selector) {
var el = this;
while (el) {
if (el.matches(selector)) {
return el;
}
el = el.parentElement;
}
return null;
};
References
5. Write a function to find the corresponding node in two identical DOM trees
- Given two same DOM tree A, B, and an Element a in A, find the corresponding Element b in B. By corresponding, we mean a and b have the same relative position to their DOM tree root.
const A = document.createElement("div");
A.innerHTML = `
<div>
<div>
<div>
<div id="node1"></div>
</div>
<div>
</div>
<div>
<div>
<p id="node2"></p>
</div>
</div>
<div>
</div>`;
const B = A.cloneNode(true);
const node1 = A.querySelector("#node1");
const node2 = A.querySelector("#node2");
const node1Target = B.querySelector("#node1");
const node2Target = B.querySelector("#node2");
findCorrespondingNode(A, B, node1); // node1Target
findCorrespondingNode(A, B, node2); // node2Target
const findCorrespondingNode = (rootA, rootB, target) => {
if (rootA === target) return rootB;
if (rootA.childElementCount) {
for (let i = 0; i < rootA.childElementCount; i++) {
let result = findCorrespondingNode(
rootA.children[i],
rootB.children[i],
target
);
if (result) {
return result;
}
}
}
};
References
6. Write a function to get depth of a given DOM tree
- A depth of a given DOM tree is the max depth till which DOM nodes are nested
/**
* @param {HTMLElement | null} tree
* @return {number}
*/
function getHeight(root) {
if (!root) return 0;
let maxDepth = 0;
const helper = (current, depth = 1) => {
if (current.hasChildNodes()) {
for (let child of current.children) {
helper(child, depth + 1);
}
}
maxDepth = Math.max(maxDepth, depth);
};
helper(root);
return maxDepth;
}
7. Implement a function to get the root node of a given DOM fragment (document.getRootNode() method)
- Root node is the topmost parent node of any given DOM fragment
/**
* @param {HTMLElement | null} tree
* @return {HTMLElement | null}
*/
function getRootNode(tree) {
if (!tree) return null;
while (tree.parentElement) {
tree = tree.parentElement;
}
return tree;
}
References
8. Implement a function to get unique tag names in a given DOM tree
/**
* @param {HTMLElement | null} tree
* @return {Array}
*/
function getUniqueTags(root, result = new Set()) {
if (!root) return [];
if (!result.has(root.tagName)) {
result.add(root.tagName);
}
if (root.hasChildNodes()) {
for (let child of root.children) {
getUniqueTags(child, result);
}
}
return [...result];
}
References
9. Implement a function to get elements by tag name (document.getElementsByTagName() method)
- The getElementsByTagName method of Document interface returns an HTMLCollection of elements with the given tag name.
- For example, document.getElementsByTagName(‘div’) returns a collection of all div elements in the document.
/**
* @param {HTMLElement | null} tree
* @return {Array}
*/
function getElementsByTagName(root, tagName) {
if (!root) return [];
let result = [];
if (root.tagName.toLowerCase() === tagName.toLowerCase()) {
result.push(root);
}
if (root.hasChildNodes()) {
for (let child of root.children) {
result = result.concat(getElementsByTagName(child, tagName));
}
}
return result;
}
References
10. Implement a function to check if a given DOM tree has duplicate IDs
- In a given DOM tree, the id on each node has be unique
- Although HTML is very forgiving, but we should avoid duplicate identifiers
/**
* @param {HTMLElement | null} tree
* @return {Boolean}
*/
function hasDuplicateId(tree, idSet = new Set()) {
if (!tree) return false;
if (idSet.has(tree.id)) return true;
tree.id && idSet.add(tree.id);
if (tree.hasChildNodes()) {
for (let child of tree.children) {
const result = hasDuplicateId(child, idSet);
if (result) return true;
}
}
return false;
}
11. Implement a function to get all descendants of a given DOM node
- This function retrieves all child elements, regardless of depth.
/**
* @param {HTMLElement | null} tree
* @return {Array}
*/
function getAllDescendants(root) {
if (!root) return [];
let descendants = [];
const helper = (node) => {
if (node) {
descendants.push(node);
if (node.children.length) {
for (let child of node.children) {
helper(child);
}
}
}
};
helper(root);
return descendants;
}
References
12. Implement a function to clone a DOM tree
- This function creates a deep copy of the given DOM node and its descendants.
/**
* @param {HTMLElement | null} tree
* @return {HTMLElement | null}
*/
function cloneDOMTree(root) {
return root ? root.cloneNode(true) : null;
}
References
13. Implement a function to count all elements in a DOM tree
- This function counts all child elements, regardless of depth.
/**
* Counts all child elements in a DOM tree.
*
* @param {HTMLElement | null} root - The root element from which to start counting.
* @return {number} - The total number of child elements.
*/
function countElements(root) {
if (!root) return 0;
let count = 1;
for (let child of root.children) {
count += countElements(child);
}
return count;
}
14. Implement a function to serialize a DOM tree into a string
- This function converts a DOM tree into a string representation.
/**
* @param {HTMLElement | null} tree
* @return {string}
*/
function serializeDOM(root) {
if (!root) return '';
let str = `<${root.tagName.toLowerCase()}`;
for (let attr of root.attributes) {
str += ` ${attr.name}="${attr.value}"`;
}
str += '>';
if (root.hasChildNodes()) {
for (let child of root.children) {
str += serializeDOM(child);
}
}
str += `</${root.tagName.toLowerCase()}>`;
return str;
}
References
15. What is event delegation in the DOM and how can it be implemented in JavaScript?
- Event delegation allows you to attach a single event listener to a parent element to manage events from its child elements, leveraging event bubbling. This improves performance and simplifies handling dynamically added elements.
Here’s an example of how event delegation works:
document.querySelector('#parent').addEventListener('click', function(event) {
if (event.target && event.target.matches('button')) {
console.log('Button clicked:', event.target.textContent);
}
});
This approach optimizes performance and reduces memory usage, as fewer event listeners are attached to individual elements.
References
16. How can you find all leaf nodes in a given DOM tree?
- Leaf nodes in a DOM tree are elements that do not have any child elements. You can traverse the tree recursively to collect all leaf nodes.
Implementation:
function getLeafNodes(element) {
let leafNodes = [];
// Base case: if the element has no children, it's a leaf node
if (!element.children || element.children.length === 0) {
leafNodes.push(element);
return leafNodes;
}
// Recursive case: traverse through each child
for (let i = 0; i < element.children.length; i++) {
leafNodes = leafNodes.concat(getLeafNodes(element.children[i]));
}
return leafNodes;
}
// Example usage:
const leafNodes = getLeafNodes(document.body);
console.log('Leaf nodes:', leafNodes);
In this implementation:
The function checks if the current element has no children. If so, it adds it to the leafNodes array. Otherwise, it recursively collects leaf nodes from each child.
References
Last updated on