Control flow#
Control flow is how the operator’s program decides what runs
next. JavaScript ships if / else, switch, for /
for...of / for...in / while / do...while,
break / continue / return / throw. There is no
match keyword (proposal still in flight); object dispatch
and switch cover the common cases.
This page is the day-to-day reference. For values these branch
on, see Types. For throw / try, see
Errors.
Conditional#
if / else if / else evaluates branches top-to-bottom
and takes the first whose condition is truthy.
flowchart TD
A([start]) --> B{x > 0?}
B -->|true| C[positive]
B -->|false| D{x === 0?}
D -->|true| E[zero]
D -->|false| F[negative]
C --> Z([end])
E --> Z
F --> Z
if (x > 0) {
positive();
} else if (x === 0) {
zero();
} else {
negative();
}
The ternary cond ? a : b is the expression form.
const label = n % 2 === 0 ? "even" : "odd";
Useful when the branch fits one expression.
const z = a > 0 ? a : -a;
Switch#
switch dispatches on a value with === semantics. Cases
fall through to the next case unless write break.
flowchart TD
A([switch cmd]) --> B{"start | go"}
B -->|yes| C[run]
B -->|no| D{stop}
D -->|yes| E[halt]
D -->|no| F[default: throw]
C --> Z([break out])
E --> Z
switch (cmd) {
case "start":
case "go":
run();
break;
case "stop":
halt();
break;
default:
throw new Error(`unknown: ${cmd}`);
}
For type-style dispatch, the operator increasingly reaches for an
object-as-table pattern rather than switch.
const handlers = {
start: run,
stop: halt,
};
(handlers[cmd] ?? unknown)(cmd);
Loops#
Four forms. Pick by what the operator is iterating.
flowchart TD
A([init]) --> B{cond?}
B -->|true| C[body]
C --> D[step]
D --> B
B -->|false| E([end])
For (C-style)#
Init, condition, step. Best when the operator needs a numeric counter or a non-iterable walk.
for (let i = 0; i < 10; i++) {
console.log(i);
}
For…of#
Walks any iterable (arrays, strings, Map, Set,
generators, anything implementing Symbol.iterator). The
operator’s default for collection iteration.
for (const item of items) handle(item);
for (const ch of "operator") console.log(ch);
for (const [k, v] of Object.entries(obj)) console.log(k, v);
For…in#
Walks enumerable string keys of an object, including
inherited ones. Rarely the right tool; Object.keys /
Object.entries plus for...of is clearer and avoids
inherited keys.
for (const k in obj) {
if (Object.hasOwn(obj, k)) console.log(k, obj[k]);
}
While and do…while#
while tests first; do...while tests after the body has
run once.
while (queue.length) handle(queue.shift());
do {
line = await readLine();
process(line);
} while (line !== "quit");
Jumps#
Keyword |
Effect |
|---|---|
|
Exit the innermost loop or |
|
Skip the rest of the loop body, jump to the next iteration. |
|
Exit the current function with a value (default
|
|
Raise an exception (see Errors). |
outer: for (const row of rows) {
for (const cell of row) {
if (cell === target) break outer; // jump out of both loops
}
}
for (const line of lines) {
if (line.startsWith("#")) continue; // skip comments
process(line);
}