For too long (about a few weeks), I have second guessed myself every time I've started writing a For... loop. Here, I will show you how to know which one you should use for the task at hand, what can happen when you choose the wrong one, and how this extends to DOM elements.
For... of
When handling arrays of data, using a For...of loop is a great option.
Every time the loop is entered here, a new entry from the array is loaded into the value of i. The first console.log here will show i as being equal to the value of array[0], or 'apple'. The second as 'banana' and so on. Note that i is not equal to the index value of the item.
For... in
Now for objects, a For...in loop is what you want to use. I like to imagine that I'm looking inside of the object to see all the keys and values.
For this type of loop, every time i is reassigned, it gets a new key. Now, let's change our objectLogger function to see if we can view the values instead.
By choosing to log object[i] instead of i, we can see every value in our object. So by using this type of loop, we can gain complete insight into every key:value pair in our object. An important thing to keep in mind when accessing objects like this is to NOT use dot notation and instead use the computed member access operator, aka brackets, for getting object properties. In this function, attempting to console.log object . i results in an undefined error as JavaScript tries to look through the object for a key literally called i.
What happens if we forget?
In the case of trying to treat an object as if it were an array, disastrous consequences will immediately occur and your IDE will make that clear as soon as you try to run the code.
arrayLogger(animalObject)
// will return the following:
index.js:6 Uncaught TypeError: array is not iterable
at arrayLogger (index.js:6:25)
at HTMLDocument.<anonymous> (index.js:24:5)
However, in the case of treating an array as an object, something interesting happens.
objectLogger(fruitArray)
//=> apple, banana, cantaloupe
You are actually able to treat an array as an object in JavaScript, because it is a subtype of object.
Check it out:
console.log(typeof fruitArray)
//=> object
console.log(typeof animalObject)
//=> object
Interesting. This is also why it is also a terrible idea to use the typeof operator to distinguish between an array and an object.
DOM Elements and Notes on Handling Them
After some experimentation on a beautiful HTML page, I've been able to get a better handle on what exactly happens when putting together a collection of HTML/Node elements.
The relevant portion of my test HTML file.
I'll spare you the eye-searing entirety of the output.
So let's see what happens when we gather the elements up in HTML collection form.
const divItems = document.getElementsByTagName('div')
console.log(divItems)
//=> HTMLCollection(7) [div, div, div, div, div, div, div]
for (const i of divItems) {
console.log(i)
}
// will output :
// <div>Hey</div>
// <div>it's</div>
// <div>a</div>
// <div>whole</div>
// <div>bunch</div>
// <div>of</div>
// <div>divs!</div>
Okay, so this HTML collection is a type of array. But what if we handle it like an object?
for (const i in divItems) {
console.log(i)
}
// will output the following (numbers on one line for readability)
// 0, 1, 2, 3, 4, 5, 6
// length
// item
// namedItem
Whoa, secret properties. So this is why an HTML collection is a bit more substantial than a mere array. But let's get into the far superior querySelectorAll to see why I make that claim in the first place.
const divList = document.querySelectorAll('section div')
console.log(divList)
//=> NodeList(7) [div, div, div, div, div, div, div]
for (const i of divItems) {
console.log(i)
}
// will output :
// <div>Hey</div>
// <div>it's</div>
// <div>a</div>
// <div>whole</div>
// <div>bunch</div>
// <div>of</div>
// <div>divs!</div>
Alright so far, pretty much the same. Except it's called a NodeList. Whatever, right? But hang on, let's try to read it like an object.
for (const i in divItems) {
console.log(i)
}
// will output the following (numbers on one line for readability)
// 0, 1, 2, 3, 4, 5, 6
// entries
// keys
// values
// forEach
// length
// item
And there's why I like a NodeList more. It has the forEach method available for use because it is inherited from its Prototype (maybe I'll write about that later). If you expand the console.log for the HTML/Node collection as a whole and look at the last entry, you can spot the additional object 'keys' that are read by a For...in loop.
Peering inside our HTML collection entry.
So if your goal is to iterate through bunch of HTML elements on a page, your best best is to querySelectorAll those bad boys and either use a For...of loop or a forEach method on them.
TL;DR
Use a For... of loop on an array when you want to know the 1st, 2nd, or nth item of the array. Use a For... in loop on an object when you want to see the key:value pairs inside it. HTMLCollections and NodeLists are both a type of array, but only a NodeList has access to the forEach method.
Thanks for reading!
Top comments (0)