JavaScript Control Flow and Declarations
Learn how JavaScript chooses execution paths, creates block-scoped bindings, exits functions, handles exceptions, and applies automatic semicolon insertion.
Intermediate
JavaScript does not execute every line in a simple top-to-bottom sequence. Statements can choose a branch, repeat or skip work, leave a function, raise an exception, or recover from one. Declarations also create bindings whose scope and timing matter. This lesson builds the control-flow model that later lessons will rely on.
1. Blocks group statements and create lexical scope
A block is the sequence between
{ ... }. A block groups statements for control-flow purposes, and lexical declarations such as
let and
const are scoped to that block. A declaration inside a block is not automatically visible outside it.
Output
Ready to run.
Quick check
Which declaration is available outside the braces?
let message = "outside";
{
const inside = "block value";
}
console.log();
2. Declarations create bindings; expressions produce values
A declaration introduces a binding or other declared entity. An expression evaluates to a value.
const total = price * quantity; combines a lexical declaration with an initializer expression. Keeping the two ideas separate makes later control-flow syntax easier to read.
Output
Ready to run.
Quick check
In const total = price * quantity;, which part is the initializer expression?
const total = ;
3. Conditions choose which statements run
An
if statement evaluates its condition and executes one branch when the result is truthy. With
else if and
else, JavaScript selects the first matching branch and does not execute the later alternatives.
Output
Ready to run.
Quick check
With score = 82, which branch runs?
const score = 82;
if (score >= 80) {
console.log(
}
4. switch selects a case, and break controls fall-through
A
switch statement compares its discriminant with case values using strict comparison semantics. Once a matching case is selected, execution continues through subsequent statements until a
break or the end of the switch is reached. Deliberate fall-through is possible, but accidental fall-through is a common bug.
Output
Ready to run.
Quick check
What does break do in a switch case?
switch (command) {
case "save":
result = "Saving";
}
5. break and continue change loop control
The existing loops lesson introduces iteration syntax. Here the focus is control transfer inside an iteration:
continue skips the rest of the current iteration, while
break exits the nearest enclosing loop. They change where execution resumes; they do not change the loop condition itself.
Output
Ready to run.
Quick check
When value is 3 in the example, what happens?
for (const value of [1, 2, 3]) {
if (value === 3) ;
}
6. return leaves a function and supplies its result
A
return statement exits the current function. With an expression, that expression becomes the function result; without an expression, the function returns
undefined. A return statement does not merely “print” a value—it transfers control back to the caller.
Output
Ready to run.
Quick check
What does return "pass" do?
function label() {
}
7. throw transfers control as an exception
The
throw statement creates an abrupt completion with the value you throw. If nothing catches that exception in the current execution path, it propagates outward. Throwing an
Error object is a common way to carry a useful error name and message.
Output
Ready to run.
Quick check
What happens immediately after throw new Error("A name is required")?
try {
throw new Error();
} catch (error) {
console.log(error.message);
}
8. try, catch, and finally separate failure handling from cleanup
A
try block contains code that may throw. A matching
catch block receives the thrown value. A
finally block runs after the try/catch path, including when control leaves through an exception or return. Use finally for cleanup that should happen regardless of success or failure.
Output
Ready to run.
Quick check
Which block is intended for work that should run whether the try succeeds or fails?
try {
riskyWork();
} catch (error) {
recover(error);
} { cleanup(); }
9. Automatic semicolon insertion has specific rules
JavaScript can insert semicolons automatically in defined grammar situations, but it does not simply put a semicolon after every newline. Restricted productions such as
return make line breaks significant. The safest authoring habit is to keep the expression returned by
return on the same line and to avoid formatting that depends on a guessed insertion point.
Output
Ready to run.
Quick check
What does return followed by a line break before 42 return?
function example() {
return
;
}
10. Put control-flow constructs together
Real programs combine declarations, conditions, loops, return, and exception handling. The important skill is tracing where execution can go next. Read each branch as a possible path rather than assuming every statement runs.
Output
Ready to run.
Quick check
In classify([2, 0, 12]), which statement ends the function?
if (value > 10) ;
Authoring rules
Key takeaways
- Blocks group statements and give lexical declarations a block scope.
- Control-flow statements change which statements execute next; they do not all produce ordinary expression values.
- break exits a loop or switch, continue skips to the next loop iteration, return exits a function, and throw creates an exception completion.
- catch handles an exception; finally is the place for cleanup that should run after the try path.
- Automatic semicolon insertion follows grammar rules. Do not rely on a newline behaving like a semicolon in every context.
Practice what you learned
Use the control flow and declarations code-completion exercise and then take the control flow and declarations quiz.
Specification reference
This lesson is based on the current ECMAScript Language Specification (ECMA-262), especially Statements and Declarations and the lexical grammar rules for Automatic Semicolon Insertion. The specification describes the exact grammar and runtime semantics behind these control-flow operations.
ECMA-262 — Statements and Declarations
ECMA-262 — Automatic Semicolon Insertion
Next step
Next, deepen the execution model with lexical scope, environments, temporal dead zones, function scope versus block scope, and closures.
Thanks for your feedback.
Mark this learning resource complete to track your learning progress.