Skip to content
Foxipa

Suggest an edit

Tell us what should be corrected, clarified, or improved. Submission will be connected to Foxipa’s contribution service later.

No information is sent anywhere yet. Your suggestion is only prepared in your browser.

Learning

JavaScript Control Flow and Declarations

Learn how JavaScript chooses execution paths, creates block-scoped bindings, exits functions, handles exceptions, and applies automatic semicolon insertion.

Levels: Intermediate ~32 min read

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.

Interactive Runnable example
Edit

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.

Interactive Runnable example
Edit

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.

Interactive Runnable example
Edit

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.

Interactive Runnable example
Edit

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.

Interactive Runnable example
Edit

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.

Interactive Runnable example
Edit

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.

Interactive Runnable example
Edit

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.

Interactive Runnable example
Edit

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.

Interactive Runnable example
Edit

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.

Interactive Runnable example
Edit

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.

Was this page helpful?

Mark this learning resource complete to track your learning progress.