For years developers would want to do something link this:
// Example 1
var myNodeList = document.querySelectorAll('div');
myNodeList.forEach(node => node.classList.add('blue'));
and would get an error like this: Uncaught TypeError: myNodeList.forEach is not a function
The error would occur because, although a node list looks like an array when you inspect it via console.log()
, it is in fact not an array and lacked typical array methods, like forEach()
. To solve the problem of iterating over a node list, you would have to create a new array based on the node list, like this:
// Example 2: Old way
var myNodeList = document.querySelectorAll('div');
const myNodeListAsArray = Array.prototype.slice.call(myNodeList);
// another way to convert a node list to an array:
// ~thanks Mark (Twitter: @markpinero) for the tip!~
// const myNodeListAsArray = [...myNodeList];
myNodeListAsArray.forEach(node => node.classList.add('blue')
These days a node list still isn't an array, but it is iterable with the forEach()
method. Now 'Example 1' above executes without any problems!
Here's a somewhat 'real-world' example:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Iterable Node List</title>
<style>
.nodes {
display: flex;
}
.nodes > div {
height: 80px;
width: 80px;
background-color: lightgray;
margin: 10px;
}
.nodes > div.blue {
background-color: lightblue;
}
.nodes > div.green {
background-color: lightgreen;
}
</style>
</head>
<body>
<div class="nodes">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<script type="text/javascript">
function addGreenClassNewWay() {
const nList = document.querySelectorAll(".nodes > div");
nList.forEach(node => node.classList.add("green"));
}
function addBlueClassOldWay() {
var myNodeList = document.querySelectorAll("div");
const myNodeListAsArray = Array.prototype.slice.call(myNodeList);
myNodeListAsArray.forEach(node => node.classList.add("blue"));
}
const button = document.createElement("button");
button.innerText = "Add color";
// button.onclick = addBlueClassOldWay;
button.onclick = addGreenClassNewWay;
document.querySelector("body").appendChild(button);
</script>
</body>
</html>
Javascript is progressing very quickly these days, and, although it can be hard to keep up sometimes, all these changes seem to be for the better. If you like old-school javascript, no problem - ES5 isn't going anywhere. However, if you're excited about new language features and APIs, then these are exciting times indeed.