JavaScript Interview Questions — Harder DOM Questions

John Au-Yeung - Jan 24 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

To get a job as a front end developer, we need to nail the coding interview.

In this article, we’ll look at some harder questions about DOM manipulation.

How to check if an element is a descendant of a parent element?

We can use the parentNode property of a DOM element to check if an element is a child of another element.

For example, we write the following function check if a node is a parent of a child node:

const isDescendant = (parent, child) => {
  while (child.parentNode) {
    if (child.parentNode == parent)
      return true;
    else
      child = child.parentNode;
  }
  return false;
}
Enter fullscreen mode Exit fullscreen mode

In the isDescendant function, we get the parent node of the child with the parentNode property until we reach the top level.

In each parent, we check if the parentNode property references the same node as the parent .

We return true if that’s the case. Otherwise, we go top the grandparent, great-grandparent and all the way to the top level and return true if we find that parentNode is the same node as parent.

Otherwise, we return false if none of them are the same as parent.

For example, if we have the following HTML:

<div>
  <p>
    <span></span>
  </p>
</div>

<div id='foo'></div>
Enter fullscreen mode Exit fullscreen mode

Then if we have the following code:

const div = document.querySelector('div');
const p = document.querySelector('p');
const span = document.querySelector('span');
const foo = document.querySelector('#foo');

console.log(isDescendant(div, p));
console.log(isDescendant(div, span));
console.log(isDescendant(foo, span));
Enter fullscreen mode Exit fullscreen mode

The first 2 should log true and the last one should false since the first div is the parent of p and grandparent of the span.

The div with ID foo isn’t a parent of any of the other nodes.

What’s the difference between innerHTML and appendChild?

innerHTML removes all current child nodes of the elements. Then the JavaScript interpreter parses the string and then assigns the parsed string to the element as the children.

appendChild attaches the child node to the parent node it’s called on as the name suggests.

For example, if we have the following HTML:

<div>
  <p>foo</p>
</div>
Enter fullscreen mode Exit fullscreen mode

Then if we write:

const div = document.querySelector('div');
div.innerHTML = '<p>bar</p>';
Enter fullscreen mode Exit fullscreen mode

Then we only see ‘bar’ on the screen since we set the innerHTML property to overwrite what’s there.

On the other hand, if we use appendChild as follows:

const div = document.querySelector('div');

const p = document.createElement("p");
const bar = document.createTextNode("bar");
p.appendChild(bar);

div.appendChild(p);
Enter fullscreen mode Exit fullscreen mode

Then we add the p element with the text node ‘bar’ and the call appendChild to append p to the div , we see:

foo

bar
Enter fullscreen mode Exit fullscreen mode

displayed on the screen since we added a new child to the end of the list of child elements to the div.

What is createDocumentFragment and why you might use it?

document.createDocumentFragment lets us create a new DocumentFragment in which DOM nodes can be added to build an offscreen DOM tree.

For example, if we have the following HTML:

<ul></ul>
Enter fullscreen mode Exit fullscreen mode

Then we can use createDocumentFragment as follows to create an offscreen fragment and then insert the whole thing into the DOM:

const element = document.querySelector('ul');
const fragment = document.createDocumentFragment();
const fruits = ['apple', 'orange', 'grape'];

fruits.forEach((fruit) => {
  const li = document.createElement('li');
  li.textContent = fruit;
  fragment.appendChild(li);
});

element.appendChild(fragment);
Enter fullscreen mode Exit fullscreen mode

With createDocumentFragment , we added all the nodes to fragment first and then append the whole thing to our ul element with appendChild .

DocumentFragment is a lightweight or minimal part of a DOM or a DOM subtree. It’s useful for manipulating the part of the DOM multiple times.

DocumentFragments are managed in memory so that the CPU won’t be taxed by expensive operations.

What is reflow? What causes reflow? How could we reduce reflow?

Reflow is the situation where we change the position of the elements according to screen size or position changes.

If we change the width of the screen, like when we’re rotating the phone’s screen, then everything has to be moved to display in the screen property.

Reflows are expensive since everything has to be moved, especially on smaller devices like phones.

Reflows are caused by changing layout, resizing the window, changing the dimension of any element, changing fonts in any way, moving DOM elements, adding or removing stylesheets, and anything else that make similar kinds of changes.

To avoid reflow, we avoid setting multiple inline styles, apply animations to elements that fixed or absolute position, and avoid using tables for layout.

Conclusion

We can use the parentNode property of a node to get the parent of a node.

Setting the innerHTML property of an element overwrites all the existing children and replace them with new ones from the string we set.

appendChild attaches a new child element to the end of the subtree.

DocumentFragments are lightweight offscreen elements that hold DOM elements. It’s managed in memory and can be added to the screen like any other element.

Reflow is the position change of elements according to some other changes on the screen. It’s an expensive operation that should be avoided.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .