In JavaScript, an empty statement is used to provide no statement where a statement is expected. The opposite is a block statement, which is used to provide multiple statements where only one statement is expected.

In my experience, empty statements are most common in for loops. Consider a simple loop that prints the numbers from 1 to 10:

for (let i = 1; i <= 10; i++) console.log(i);
  1. The first expression is evaluated once before the loop begins.
  2. The second expression is evaluated before each iteration.
  3. The third expression is evaluated at the end of each iteration.

Did you know that all three expressions are optional? You can use empty statements to omit them!

For example, if the i variable is already in scope, you can omit the first expression:

let i = 1;
for (; i <= 10; i++) console.log(i);

If you move the condition to the body of the loop, remembering to use a break statement, you can omit the second expression:

for (let i = 1; ; i++) {
if (i > 10) break;
console.log(i);
}

If you increment the counter in the body of the loop, you can omit the third expression:

for (let i = 1; i <= 10; ) {
console.log(i);
i++;
}

You can omit more than one expression, such as the first and second:

let i = 1;

for (; ; i++) {
if (i > 10) break;
console.log(i);
}

Or the second and third:

for (let i = 1; ; ) {
if (i > 10) break;
console.log(i);
i++;
}

Or the first and third:

let i = 1;

for (; i <= 10; ) {
console.log(i);
i++;
}

Or even all three:

let i = 1;

for (;;) {
if (i > 10) break;
console.log(i);
i++;
}

Just because you can do this doesn’t mean you should. There are definitely more readable ways to write these loops. But it’s important to understand that this is syntactically valid JavaScript, because you might see it in someone else’s code.