There are two key things you need to properly define when working with loops in JavaScript: enumerable properties
and iterable objects
.
One defining characteristic of an enumerable object is that we set the internal enumerable flag to true when we assign a property to an object via the assignment operator. This is the default value.
However, we can change this behavior by setting it to false.
A rule of thumb is that an enumerable property always shows up in a for … in
loop.
Let’s see this in action:
// shows up in a for .... in loop const gbols = {}; gbols.platform = "LogRocket"; Object.getOwnPropertyDescriptor(gbols, "platform") {value: "LogRocket", writable: true, enumerable: true, configurable: true} // doesn't show up in a for .... in loop //to have more control of this properties we use Object.defineProperty(gbols, 'role', {value: 'Admin', writable: true, enumerable: false}) // Testing this out yeilds for (const item in gbols) { console.log(item) } // logs platform
An object is iterable if it defines its iteration behavior. The value that will be looped over in a for …of
construct, in this case, would define its iteration behavior. Built-in types that are iterable include Arrays
, Strings
, Sets
, and Maps
An object
is not iterable because it does not specify an @iterator method
.
Basically, in Javascript, all iterables are enumarables, but not all enumerables are iterables.
Here’s a way to conceptualize this: for …in
looks for the object in the data, while for ..of
looks for repetitive sequences.
Let’s see how this all looks when used with an Array
data type:
const authors = ['Jade', 'Dafe', 'Gbols', 'Daniel']; // using with a for in loop for (const author in authors) { console.log(author) } // logs 0,1,2,3 for (const author of authors) { console.log(author) } // logs Jade, Dafe, Gbols, Daniel
Something to keep in the back of your mind when using this constructs is that if typeof
is called and the answer yields object
, then you can use a for …in
loop.
Let’s look at this operation on the author’s variable:
typeof authors // logs "object" hence we can use a for ..in
This may seem surprising at first, but it’s important to note that arrays are a special kind of object with indexes as the key. Knowing that for ...in
will look for an object in a construct can help us tremendously. When a for ...in
loop finds an object, it will loop over each key.
We can visualize the way the for ..in
loops over the author arrays as follows:
const authors = { 0: 'Jade', 1: 'Dafe', 2: 'Gbols', 3: 'Daniel' }
An important note: if it can be traced to an object (or inherits it from the object prototypal chain), for …in
will iterate over the key in no particular order.
Meanwhile, if it implements an iterator for.. of
construct, it will loop over the value in each iteration.
ForEach
and map
methodsWhile forEach
and map
methods can be used to achieve the same thing, there are differences in their behavior and peculiarities about their performance.
At the base level, they both receive a callback as an argument when the function is called.
Consider the following snippet:
const scoresEach = [2,4 ,8, 16, 32]; const scoresMap = [2,4 ,8, 16, 32]; const square = (num) => num * num;
Let’s itemize a few differences in their operation.
forEach
returns undefined
, while map
returns a new array
:
let newScores = [] const resultWithEach = scoresEach.forEach((score) => { const newScore = square(score); newScores.push(newScore); }); const resultWithMap = scoresMap.map(square); console.log(resultWithEach) // logs undefined console.log(resultWithMap) // logs [4, 16, 64, 256, 1024]
Map
is a pure function, while forEach
performs some mutation:
console.log(newScores) // logs [4, 16, 64, 256, 1024]
In my opinion, map
favors the functional programming paradigm. We don’t always have to perform a mutation to get back the desired result, unlike forEach
, where we had to mutate the newScores
variable. On each run, when provided with the same input, the map
function will produce the same result. Meanwhile, the forEach
counterpart will pick up from the previous value of the last mutation.
Chaining is possible with map
, since the result returned is an array
. Therefore, any other array method can be immediately called on the result. In other words, we can call filter
, reduce
, some
, etc. This isn’t possible with forEach
, as the value returned is undefined.
The map
method tends to perform better than the forEach
method. You can use JsPerf
to check the performance of an equivalent code block implemented with map
and forEach
. On average, you’ll see that the map
function performs at least 50 percent faster.
NB: This benchmark depends on the machine you’re using, as well as your browser implementation.
Of all the looping constructs discussed above, the one that gives us the most control is the for..of
loop. We can use it with the keywords return
, continue
, and break
. This means we can specify what we want to happen to each element in an array
, and whether or not we want to leave early or skip.
With this information in mind, make sure to use the appropriate tool based on what you hope to achieve in your code.
Debugging code is always a tedious task. But the more you understand your errors, the easier it is to fix them.
LogRocket allows you to understand these errors in new and unique ways. Our frontend monitoring solution tracks user engagement with your JavaScript frontends to give you the ability to see exactly what the user did that led to an error.
LogRocket records console logs, page load times, stack traces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowThe useReducer React Hook is a good alternative to tools like Redux, Recoil, or MobX.
Node.js v22.5.0 introduced a native SQLite module, which is is similar to what other JavaScript runtimes like Deno and Bun already have.
Understanding and supporting pinch, text, and browser zoom significantly enhances the user experience. Let’s explore a few ways to do so.
Playwright is a popular framework for automating and testing web applications across multiple browsers in JavaScript, Python, Java, and C#. […]