Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 4

Controlling Program Flow with Conditionals and Switch Statements

Recommended resources

Hello! Last time, you built expressions that calculate task counts and answer questions such as remaining > 0. Today you’ll put those answers to work. A conditional statement lets your program run different code depending on what is true; a switch lets it choose among several exact values.

You’ll keep using app.js and Node.js. Allow about 40 minutes to read, edit the program, and rerun it with different values. These decisions are JavaScript behavior you’ll still rely on when you begin writing TypeScript.


Make a decision with if and else

Start with a short reading from Conditional branching: if, '?' on javascript.info. Its examples use browser pop-ups; focus on the branching syntax rather than trying to run prompt or alert in Node.js.

Conditional branching: if, '?'

Read the explanations of if, else, and else if to see how a condition controls which block runs.

Under “The ‘if’ statement,” read the if explanation, paying particular attention to parentheses and curly braces. Skim “Boolean conversion” for the reminder that a condition can be truthy or falsy. Then read “The ‘else’ clause” and “Several conditions: ‘else if’,” starting at the alternative branches and continuing through the note that the final else is optional. Leave the later section on the ? operator for another time.

Replace app.js with this task-status program, then run node app.js:

const plannedTasks = 7;
const completedTasks = 2;
const isSignedIn = true;
const remaining = plannedTasks - completedTasks;

if (isSignedIn && remaining > 0) {
  console.log("Tasks to do:", remaining);
} else {
  console.log("No tasks to display.");
}

The condition combines two checks you already know. If both are true, Node.js prints Tasks to do: 5. Otherwise, it prints the other message. Only one of these two blocks runs. Try changing isSignedIn to false, then change it back and set completedTasks to 7. Save and rerun after each change to see why the else block was selected.

An else is optional. An if on its own can perform an action only when a condition is true. Keep the braces even for a one-line block: they make it clear which statements the condition controls. Statements after the entire conditional run regardless of which branch was chosen.

The condition need not be a literal boolean. For instance, if (remaining) treats zero as falsy and a nonzero number as truthy. In this program, remaining > 0 is clearer: it says that a positive count is required and does not accidentally treat a negative count as work to do.



Handle more than two outcomes

The first program gives the same “No tasks to display” message to someone who is signed out and someone who has completed everything. Those situations call for different messages. Replace only the if...else statement in app.js with this chain:

if (!isSignedIn) {
  console.log("Sign in to see tasks.");
} else if (remaining < 0) {
  console.log("Check the task counts.");
} else if (remaining === 0) {
  console.log("All tasks complete.");
} else if (remaining <= 2) {
  console.log("Nearly there:", remaining, "tasks left.");
} else {
  console.log("Tasks to do:", remaining);
}

JavaScript checks the conditions in order and runs the first matching block. It then skips the rest of the chain. With the original values, the final else prints Tasks to do: 5. If completedTasks is 6, the “Nearly there” branch runs.

Order is part of the program’s meaning. The remaining === 0 check comes before remaining <= 2 because zero also satisfies “at most two.” The negative-count check comes earlier still, so an impossible count gets its own warning. The first check gives the signed-out message priority over all task-count messages.

To trace this behavior, edit the declarations at the top of the file and rerun with completedTasks set to 5, 7, and 8. For the last value, remaining is negative. You can also set isSignedIn to false while remaining is negative: the first branch still wins. When rules overlap, decide deliberately which one should take priority.

You could write several independent if statements, but then more than one block might run. An if...else if...else chain expresses a choice of one outcome. It is useful here because the rules involve different kinds of checks: a signed-in flag, a negative number, zero, and a range.



Choose among exact values with switch

Now suppose a task has a status string: "todo", "in_progress", or "done". You want a different message for each value. Watch JavaScript for Beginners #8 - Switch Statements from Tech With Tim. The demonstration changes a webpage; you’ll use console.log to apply the same control flow in Node.js.

JavaScript for Beginners #8 - Switch Statements

Watch how case, break, and default work when one value is compared against several choices. The brief contrast near the end explains why numeric ranges are better handled with if...else if.

Watch cases and breaks for the basic structure, then more cases for default. Finally, skip to the comparison between exact matches and ranges. Focus on which code executes; the webpage setup is not needed for your app.js program.

Add this code after your task-count conditional:

const taskStatus = "in_progress";

switch (taskStatus) {
  case "todo":
    console.log("This task is ready to start.");
    break;
  case "in_progress":
    console.log("Keep working on this task.");
    break;
  case "done":
    console.log("This task is complete.");
    break;
  default:
    console.log("Unknown task status:", taskStatus);
}

A switch evaluates the expression in parentheses and looks for a matching case. Here it prints Keep working on this task. The break stops execution of the switch after that case. If no case matches, default handles the value instead.

The input is checked against several case values, with a default path when none matches. The depicted cases end with `break`, so execution leaves the switch after a match.

Change taskStatus to "done" and rerun; then try "paused". The latter reaches default. Matches are exact: "Done" does not match "done", and the number 1 does not match the string "1".

Do not forget break when you intend only one case to run. Without it, execution continues into the statements under the next case, whether or not that next label matches. This is called fall-through. Sometimes fall-through is intentional: two labels can share one action. For example, you could replace the switch above with:

switch (taskStatus) {
  case "todo":
  case "in_progress":
    console.log("This task is active.");
    break;
  case "done":
    console.log("This task is complete.");
    break;
  default:
    console.log("Unknown task status:", taskStatus);
}

Here "todo" deliberately falls through to the "in_progress" action because both statuses are treated as active. The break then prevents the "done" message from printing. Use shared cases when they genuinely mean the same thing; otherwise, include a break for each action.

The two conditionals in your file serve different purposes. The if...else if chain handles rules and ranges involving several values. The switch handles one expression with several exact matches. You could use an if...else if chain for the statuses too, but switch makes the set of named choices easy to scan.



What to carry forward

An if runs a block when its condition is truthy; else provides an alternative; and else if tests further conditions in order. In a chain, the first matching branch wins, so put overlapping rules in a deliberate order. Use switch for exact choices from one value, default for an unmatched value, and break unless fall-through is intentional.

Your program can now choose what to do, but it still handles only one set of task values per run. Next, you’ll use loops to repeat operations without writing the same statements over and over.