HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptModerate

forEach and NodeList

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
foreachandnodelist

Problem

This is loosely based on one of W3_School samples:


Hello World!
The DOM is very useful!
This example demonstrates forEach() function

var x=Array.prototype.slice.call(document.getElementsByTagName("p"));
x.forEach(function(value, index)
  { 
  document.write(value.innerHTML);
  document.write("");
  });


Please let me know if any improvements need (could) be done to the script.

Solution

The only purpose of this script appears to be to illustrate the use the Array.prototype.slice.call "idiom" and the forEach function. So it's hard to make "improvements" when the purpose of the code isn't its actual result (which is trivial).

What the code actually does can be done in a number of ways, some of which won't (directly) use forEach and/or NodeList and/or slice.call. In that case, is it still an improvement? Conversely, sticking to forEach etc. doesn't leave much room for change, since the code seems designed as a minimal example of those things.

I'm hesitant to write any code, because I'm not sure what the point would be.

With that said,

  • Don't rely on W3 Schools (this site lists several reasons and better alternatives)



  • Avoid document.write() - or use it with open eyes (see why here)



  • I'd also avoid forEach in favor of a standard for loop, since forEach is not universally supported in browsers (see caniuse.com)



  • The page's text appears to betray some confusion. Yes, the DOM is useful, and yes, the code demonstrates forEach. But forEach isn't part of the DOM. The whole point is that a NodeList object is a DOM object and not a normal array. It must therefore be converted to one by way of Array.prototype.slice.call. Then one can use forEach which is an array function but which, in and of itself, has nothing to do with the DOM.



Update after reading @PM77-1's comment:

There's nothing inherently wrong with this code. It is true, that

A) for...in doesn't behave like it does in Java and shouldn't be used here, and that

B) getElementsByTagName doesn't return a "real" array. The slice.call trick is indeed the "standard" way of converting an "array-like" object (which you find a lot of, unfortunately) to a real array. A very useful trick to know.

So all in all, the code is basically fine. Yes, improvements can be made, as @Palacsint points out in his answer, but there's nothing terrible going on.

However, while a NodeList object isn't a real array, one can still use a regular old for loop:

var nodes, i;

nodes = document.getElementsByTagName("p");
for(i = 0 ; i ");
}


This removes the need for the slice.call trick, and it works on old browsers (where forEach doesn't exist).

In general, though, when working with the DOM, it's useful to use a library to iron out the otherwise frustrating differences between browsers. jQuery is the king of the hill these days, and with that, you'd do something like this to find and iterate over some elements:

$("p").each(function () {
  document.write(this.innerHTML);
  document.write("");
});


(Of course, jQuery also makes it easy to do "proper" DOM insertion without resorting to document.write, but this is just for illustration)

However, I do think it very wise to learn the nitty-gritty of JS, and not just run straight for jQuery or its ilk. And dealing with those "array-like" is one of those nitty-gritty things indeed.

Code Snippets

var nodes, i;

nodes = document.getElementsByTagName("p");
for(i = 0 ; i < nodes.length ; i++) {
  document.write(nodes[i].innerHTML);
  document.write("<br>");
}
$("p").each(function () {
  document.write(this.innerHTML);
  document.write("<br>");
});

Context

StackExchange Code Review Q#44529, answer score: 11

Revisions (0)

No revisions yet.