For Loops And HTML Collections In JavaScript


My deeper, but admittedly still shallow, understanding of for...in and for...of loops
javascript

Today I was working on trying to make my own accordion-style object for my resume site.

I got to a point where I had to iterate over an HTML Collection and started to bust-out the old standby:

var accordions = document.getElementsByClassName('accordion');
for(let i = 0; i < accordions.length; i++) {
	accordions[i].style.maxHeight = 0;
	// Other accordion stuff
}

But that didn’t seem very fancy… so I decided to spice things up with a for…in loop.

var accordions = document.getElementsByClassName('accordion');
for(let accordion in accordions) {
	accordions[i].style.maxHeight = 0;
	// Other accordion stuff
}

And before I could queue up “Fancy” by Drake on Spotify, I got hit with:

Uncaught TypeError: Cannot set property 'maxHeight' of undefined

A quick Google search told me to just use a for…of loop instead, and that worked fine, but makes for a pretty boring blog post, so I did a dive into why for…of worked and for…in didn’t.

For…In Loops In JavaScript

Changing my code to log the value of accordion inside the for loop instead of changing style got me:

0
1
2
3
4
length
item
namedItem

Definitely not the nodes that I was expecting.

Looking up for…in loops in MDN lead me to:

The loop will iterate over all enumerable properties of the object itself and those the object inherits from its constructor’s prototype

Now those results kind of make sense:

  • The numbers 0 - 4 being the property names of the properties that contain my nodes
  • length, item, namedItem being inherited properties

Knowing this I could get my code to work by changing it to:

var accordions = document.getElementsByClassName('accordion');
var accordionIndexes = Object.getOwnPropertyNames(accordions);
for(let accordionIndex in accordionIndexes) {
	accordions[accordionIndex].style.maxHeight = 0;
	// Other accordion stuff
}

…but that’s uglier than what I started with.

For…Of Loops In JavaScript

Knowing from my Google search that for…of loops work, I decided to look them up in MDN and found:

The for…of statement creates a loop iterating over iterable objects (including Array, Map, Set, String, TypedArray, arguments object and so on), invoking a custom iteration hook with statements to be executed for the value of each distinct property.

So, for this to work, HTML Collection must have a built in iterator method that only iterates over the collection. Why just assume that though when we can prove it ourselves and end up with some beautiful code (that only seems to work in Firefox) like this:

var accordions = document.getElementsByClassName('accordion');
var accordionIterator = Iterator(accordions);
if(accordions.length > 0) {
	var currAccordion = accordionIterator.next();
	while(currAccordion[0] < accordions.length) {
		currAccordion[1].style.maxHeight = '0px';
		// Other accordion stuff
		currAccordion = accordionIterator.next();
	}
}

I think I’ll just stick with the for…in loop:

var accordions = document.getElementsByClassName('accordion');
for(let accordion of accordions) {
	accordion.style.maxHeight = '0px';
	// Other accordion stuff
}	

If you want to check out how I did my accordion, you can check it out on GitHub here.

comments powered by Disqus