JavaScript ES6, "For... in" vs. "For... of"

At a glance

JavaScript's ES6 (ECMAScript 6) added a whole bunch of expressive iteration methods that are just chock full of syntactic sugar! Two iteration methods in particular are fairly easy to mix-up, so this is a bit of a quick and easy introduction to ES6 iterators.

One bite: you probably want "For... of"

If you're here because you're finding yourself asking what the difference between these two methods of iteration are, you are not alone! The short and sweet answer for most JS6 students is this: "For...of" is what you're going to want for all of your iterable containers . What are iterable containers? Most of them will look familiar; MDN mentions:

[...] Strings, Arrays, array-like objects (e.g. arguments, or NodeLists), TypedArrays, Maps, Sets [...] which practically includes all of the common collection types. The noteworthy exception is "plain old Javascript objects" (or POJOs, as they're sometimes referred to), which are better served through other iteration methods. But moving past that, let's take a look at "for...of" iteration behavior:

At a glance: "For...Of" with strings

const testString = 'ABCDE';
for (const element of testString) {
  console.log(`Value: ${element}`);
}

//Value: A
//Value: B
//Value: C
//Value: D
//Value: E

The critical element to be aware of when iterating over a string with "for...of" is that the elements you'll be iterating over are all single characters. String manipulation is a fairly common task, so this pattern of iterating over a string should quickly become intuitive.

At a glance: "For...Of" with an array

const testArray = ['a', 'b', 'c', 'd', 'e'];
for (const element of testArray) {
console.log(`Value: ${element}`);
}

//Value: a
//Value: b
//Value: c
//Value: d
//Value: e

A few takeaways from "for...of" with arrays (or array-like objects): iteration happens in order, and will return the value of each element that is traversed. Iterating over collections is another one of those patterns that is ubiquitous within programming, and is another set of behaviors that will become fairly intuitive with just a little practice.

Second bite: what about "For... in"?

There's a whole rabbit hole dedicated to this particular subject, with some pretty amusing directness from the authors at MDN, such as gems like:

Given that for...in is built for iterating object properties, not recommended for use with arrays, and options like Array.prototype.forEach() and for...of exist, what might be the use of for...in at all?

The short answer is that for most JavaScript purposes, "For...in" is best used to validate the properties of an object.

At a glance: "For...In" property validation

const testObj = {
  prop1: "I'm the first property",
  keysAreAccessed: "In an arbitrary order",
  so: "Don't count on them displaying this way every time",
  }

for (const objProperty in testObj) {
  console.log(`Traversed property: "${objProperty}"  ||| property-associated val: "${testObj[objProperty]}"`);
}

//Traversed property: "prop1"  ||| property-associated val: "I'm the first property"
//Traversed property: "keysAreAccessed"  ||| property-associated val: "In an arbitrary order"
//Traversed property: "so" ||| property-associated val: "Don't count on them displaying this way every time"

forEach?

This is a neat iteration method that was added with ES6 that allows for the creation of some fairly "pretty", semantically rich iteration blocks. Many (most?) collections of data will contain samples that are somewhat similar to one another, and using the forEach iteration method can make operating on such collections much more readable. For instance, let's imagine a collection of book objects in which we want to operate on each book in some way:

const booklist = [book1, book2, ..., bookn];
booklist.forEach(book => {
     console.log(book.title);
     book.title = 'An Exploration of Ethical Iterators';
})

This block of code would iterate over every element in the collection, log the book's title, and then reassign the title to be 'An Exploration of Ethical Iterators'. This is an example of using forEach to accomplish tasks through "side effects" - this is probably one of the most important things to note about forEach as an iteration method: it has no return value. Also important to note is that forEach's iterations can not be terminated early, unlike many other iterators (including the "for...of" and "for...in" iterators mentioned above). MDN specifically suggests using either simple for loops (of the "let i = ..." flavor), .every(), .some(), .find(), or .findIndex(), as all of these methods have easy-to-implement breaks to stop unnecessary iterations.

More questions?

Supplemental reading: