All About JavaScript Loops

Publikováno: 19.8.2024

Every programming language has loops. Loops perform an operation (i.e., a chunk of work) a number of times, usually once for every item in an array or list, or to simply repeat an operation until a certain condition is met.…


All About JavaScript Loops originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Celý článek

Every programming language has loops. Loops perform an operation (i.e., a chunk of work) a number of times, usually once for every item in an array or list, or to simply repeat an operation until a certain condition is met.

JavaScript in particular has quite a few different types of loops. I haven’t even used all of them, so for my own curiosity, I thought I’d do a high-level overview of them. And as it turns out, there are pretty good reasons I haven’t used at least a couple of the different types.

So, for now let’s spend a while exploring the different types of loops, what we can do with each of one, and why you might use one over another. (You’ll think that little play on words is absolutely hilarious by the end.)

The while and do...while loops

First up is the while loop. It’s the most basic type of loop and has the potential to be the easiest to read and the fastest in many cases. It’s usually used for doing something until a certain condition is met. It’s also the easiest way to make an infinite loop or a loop that never stops. There is also the do...while statement. Really, the only difference is that the condition is checked at the end versus the beginning of each iteration.

// remove the first item from an array and log it until the array is empty
let queue1 = ["a", "b", "c"];

while (queue1.length) {
  let item = queue1.shift();

  console.log(item);
}

// same as above but also log when the array is empty
let queue2 = [];

do {
  let item = queue2.shift() ?? "empty";

  console.log(item);
} while (queue2.length);

The for loop

Next is the for loop. It should be the go to way to do something a certain number of times. If you need to repeat an operation, say, 10 times, then use a for loop instead. This particular loop may be intimidating to those new to programming, but rewriting the same loop in the while-style loop can help illustrate the syntax make it easier to stick in your mind.

// log the numbers 1 to 5
for (let i = 1; i <= 5; i++) {
  console.log(i);
}

// same thing but as a while loop
let i = 1; // the first part of a for loop

// the second
while (i <= 5) {
  console.log(i);

  i++; // the third
}

("end");

The for...of and for await...of loops

A for...of loop is the easiest way to loop through an array.

let myList = ["a", "b", "c"];

for (let item of myList) {
  console.log(item);
}

They aren’t limited to arrays though. Technically they can iterate through anything that implements what is called an iterable protocol. There are a few built-in types that implement the protocol: arrays, maps, set, and string, to mention the most common ones, but you can implement the protocol in your own code. What you’d do is add a [Symbol.iterator] method to any object and that method should return an iterator. It’s a bit confusing, but the gist is that iterables are things with a special method that returns iterators; a factory method for iterators if you will. A special type of function called a generator is a function that returns both a iterable and iterator.

let myList = {
  *[Symbol.iterator]() {
    yield "a";
    yield "b";
    yield "c";
  },
};

for (let item of myList) {
  console.log(item);
}

There is the async version of all the things I just mentioned: async iterables, async iterators, and async generators. You’d use an async iterable with for await...of.

async function delay(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

// this time we're not making an iterable, but a generator
async function* aNumberAMinute() {
  let i = 0;

  while (true) {
    // an infinite loop
    yield i++;

    // pause a minute
    await delay(60_000);
  }
}

// it's a generator, so we need to call it ourselves
for await (let i of aNumberAMinute()) {
  console.log(i);

  // stop after one hour
  if (i >= 59) {
    break;
  }
}

One unobvious thing about for await...of statement is that you can use it with non-async iterables and it will work just fine. The reverse, however, is not true; you can’t use async iterables with the for...of statement.

The forEach and map loops

While these are not technically loops per se, you can use them to iterate over a list.

Here is the thing about the forEach method. Historically it was much slower than using a for loop. I think in some cases that may not be true anymore, but if performance is a concern, then I would avoid using it. And now that we have for...of I’m not sure there is much reason to use it. I guess the only reason that it still may come up is if you have a function ready to use as the callback, but you could easily just call that same function from inside the body of for...of.

forEach also receives the index for each item though, so that may be a thing you need too. Ultimately, the decision to use it will probably come down to whether any other code you’re working with uses it, but I personally would avoid using it if I’m writing something new.

let myList = ["a", "b", "c"];

for (let item of myList) {
	console.log(item);
}

// but maybe if I need the index use forEach
["a", "b", "c"].forEach((item, index) => {
  console.log(`${index}: ${item}`);
});

Meanwhile, map essentially converts one array into another. It still has the same performance impact that forEach has, but it is a bit nicer to read than the alternative. It’s certainly subjective though, and just like with forEach you’ll want to do what the rest of your other code is doing. You see it a ton in React and React-inspired libraries as the primary way to loop through an array and output a list of items within JSX.

function MyList({items}) {
  return (
    <ul>
      {items.map((item) => {
        return <li>{item}</li>;
      })}
    </ul>
  );
}

The for...in loop

This list of loops in JavaScript wouldn’t be complete without mentioning the for...in statement because it can loop through the fields of an object. It visits fields that are inherited through the object’s prototype chain too, though, and I’ve honestly always avoided it for that reason.

That said, if you have an object literal, then for...in might be a viable way to iterate through the keys of that object. Also it’s worth noting that if you’ve been programming JavaScript for a long time, you may remember that the order of keys use to be inconsistent between browsers, but now the order is consistent. Any key that could be an array index (i.e., positive integers) will be first in ascending order, and then everything else in the order as authored.

let myObject = {
  a: 1,
  b: 2,
  c: 3,
};

for (let k in myObject) {
  console.log(myObject[k]);
}

Wrapping up

Loops are something that many programmers use every day, though we may take them for granted and not think about them too much.

But when you step back and look at all of the ways we have to loop through things in JavaScript, it turns out there are several ways to do it. Not only that, but there are significant — if not nuanced — differences between them that can and will influence your approach to scripts.


All About JavaScript Loops originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Nahoru
Tento web používá k poskytování služeb a analýze návštěvnosti soubory cookie. Používáním tohoto webu s tímto souhlasíte. Další informace