getElementsByTagName
returns an HTMLCollection
, which do not have a forEach
method. But, there's a simple tweak that will allow you to iterate with forEach
without creating an intermediate array: use querySelectorAll
instead. querySelectorAll
returns a NodeList
, and modern browsers have a NodeList.prototype.forEach
method:
document.querySelectorAll('input')
.forEach((input) => {
console.log(input.value);
});
<input type="text" value="foo">
<input type="text" value="bar">
Another benefit to using querySelectorAll
is that it accepts comma-separated CSS selectors, which are far more flexible and precise than just tag names. For example, the selector
.container1 > span, .container2 > span
will only match span
s which are children of elements with a class of container1
or container2
:
document.querySelectorAll('.container1 > span, .container2 > span')
.forEach((span) => {
span.classList.add('highlight');
});
.highlight {
background-color: yellow;
}
<div class="container1">
<span>foo</span>
<span>bar</span>
</div>
<div class="container2">
<span>baz</span>
</div>
<div class="container3">
<span>buzz</span>
</div>
If you want to use NodeList.prototype.forEach
on ancient browsers that do not have the method built-in, simply add a polyfill. The following snippet will work on IE11:
// Polyfill:
if (window.NodeList && !NodeList.prototype.forEach) {
NodeList.prototype.forEach = function(callback, thisArg) {
thisArg = thisArg || window;
for (var i = 0; i < this.length; i++) {
callback.call(thisArg, this[i], i, this);
}
};
}
// Main code:
document.querySelectorAll('.container1 > span, .container2 > span')
.forEach(function(span) {
span.classList.add('highlight');
});
.highlight {
background-color: yellow;
}
<div class="container1">
<span>foo</span>
<span>bar</span>
</div>
<div class="container2">
<span>baz</span>
</div>
<div class="container3">
<span>buzz</span>
</div>