Skip to content
academia.sh

Lesson 11 / 21

Conditions and Selection

`if` chains and guard clauses, the ternary operator, the `switch` statement's strict equality, fall-through behavior, and scope in case blocks.

Contents

The value model is complete. This topic covers building program flow with those values: which code runs under which condition, how repetition is written, and how work is split into functions. The Programming Fundamentals course’s Conditional Branching lesson established the purpose of these structures; here, JavaScript’s own particular rules are covered.

Three things about conditional selection are specific to the language: how a condition is converted to a boolean value (previous lesson), the ternary operator being an expression, and which equality switch uses.

Condition Chains and Guard Clauses

The if statement converts the expression in parentheses to a boolean value and runs the body if it is truthy. The chain continues with else if.

Guard clauses — conditions placed at the start of a chain that return early on an invalid case — rescue the real logic from nested blocks:

function classify(temperature) {
  if (temperature == null || Number.isNaN(temperature)) {
    return "invalid";
  }
  if (temperature < 18) {
    return "low";
  } else if (temperature < 22) {
    return "normal";
  } else {
    return "high";
  }
}

for (const value of [17.9, 18, 21.5, 22, 23, null, NaN]) {
  console.log(String(value).padEnd(5), classify(value));
}
17.9  low
18    normal
21.5  normal
22    high
23    high
null  invalid
NaN   invalid

The guard clause combines two checks. The == null spelling is the exception defined in the Equality Comparisons lesson: it covers both the null and undefined cases. Number.isNaN catches an invalid number; because NaN passes no comparison, without this guard classify(NaN) would silently give "high" — all three comparisons would come out false and flow would fall to the final else branch.

Which side a boundary value falls on is read from the output: 18 went to normal, 22 went to high. The choice of comparison operator (< versus <=) sets these boundaries and is part of the definition.

Curly braces are not required for single-statement bodies, but this course always writes them. The reason is that a second statement added later would otherwise silently fall outside the condition.

The Ternary Operator

if is a statement: it produces no value, it directs flow. The ternary operator is an expression: it produces a value and can be written anywhere a value is expected.

const temperature = 21.5;
const status = temperature >= 22 ? "high" : temperature >= 18 ? "normal" : "low";
console.log(status);
console.log(`${temperature} degrees: ${temperature > 20 ? "above threshold" : "below threshold"}`);
normal
21.5 degrees: above threshold

The second line shows the concrete benefit of being an expression: a condition was placed directly inside a template literal. An if statement could not have been written there.

A chained ternary associates to the right; the second question mark sits inside the first expression’s false branch. This spelling quickly loses readability past two branches. This course’s rule: a ternary is chained at most once; anything more is written as an if chain or a mapping object.

The switch Statement

switch compares a value against multiple constants. Matching is done with strict equality — one of the three operators from the Equality Comparisons lesson, ===.

function unit(field) {
  switch (field) {
    case "temperature":
      return "C";
    case "humidity":
      return "%";
    case "pressure":
      return "hPa";
    default:
      return "unknown";
  }
}
console.log(unit("temperature"), unit("humidity"), unit("wind"));
C % unknown

Using strict equality removes any expectation of coercion:

function check(value) {
  switch (value) {
    case 1:
      return "number one";
    case "1":
      return "text one";
    default:
      return "no match";
  }
}
console.log(check(1), "|", check("1"), "|", check(true));
number one | text one | no match

The number 1 and the text "1" went to separate branches. The value true matched neither — under loose equality true == 1 would be true, but switch does not use loose equality.

Fall-Through

The switch statement starts at the matching case label and flows downward until it meets a break or return. This behavior is called fall-through, and when done unintentionally it produces a silent bug:

function label(field) {
  let result = "";
  switch (field) {
    case "temperature":
      result = "temperature (C)";
    case "humidity":
      result += " humidity (%)";
      break;
    default:
      result = "unknown";
  }
  return result;
}
console.log(JSON.stringify(label("temperature")));
console.log(JSON.stringify(label("humidity")));
console.log(JSON.stringify(label("pressure")));
"temperature (C) humidity (%)"
" humidity (%)"
"unknown"

On the first line, flow fell from the first branch into the second and the two texts concatenated. This was not the writer’s intent. The outputs were written with JSON.stringify; otherwise the leading space on the second line would not be visible.

Used deliberately, fall-through binds multiple values to the same branch:

function group(station) {
  switch (station) {
    case "A1":
    case "A2":
      return "group A";
    case "B1":
      return "group B";
    default:
      return "unknown";
  }
}
console.log(group("A1"), "|", group("A2"), "|", group("B1"), "|", group("C9"));
group A | group A | group B | unknown

Empty case labels have no body; flow falls straight through to the next one. This is an accepted use of the language and is not hard to read — falling from a branch with a body into another will not be written in this course.

Scope in Case Blocks

The entire switch body is a single block. Separate case labels do not open separate scopes; this is why declaring the same name in two branches gives a parsing error:

switch (1) {
  case 1:
    const x = 1;
    break;
  case 2:
    const x = 2;
    break;
}
SyntaxError: Identifier 'x' has already been declared

The redeclaration rule from the Variable Declarations lesson shows up here in an unexpected place. The fix is to wrap each branch in its own curly braces:

switch (1) {
  case 1: {
    const x = "first";
    console.log(x);
    break;
  }
  case 2: {
    const x = "second";
    console.log(x);
    break;
  }
}
first

Choosing a Selection Structure

The choice among the three structures is made according to the shape of the comparison.

switch fits when a single value is compared against constants. Range checks, compound conditions, or a comparison other than equality call for an if chain.

Constant mappings offer a third option: they can be written as key–value pairs in an object and read directly.

const UNITS = { temperature: "C", humidity: "%", pressure: "hPa" };

function unit(field) {
  return UNITS[field] ?? "unknown";
}
console.log(unit("temperature"), unit("wind"));
C unknown

This spelling keeps its readability as the mapping grows and separates data from code. Using ?? is deliberate: if a key in the mapping had a value of 0 or an empty string, || would have dropped that to the default too.

Summary

  • Guard clauses return early on an invalid case and rescue the real logic from nested blocks; without a NaN guard, flow silently falls to the final branch.
  • The ternary operator is an expression and can be written anywhere a value is expected; it is chained at most once.
  • switch matches with strict equality; it performs no coercion.
  • Flow starts at the matching label and falls through until it meets break or return; bodyless labels bind multiple values to the same branch.
  • The switch body is a single block; to declare a name in a branch, wrap each branch in its own curly braces.
  • Constant mappings written as objects substitute for switch and take a default with ??.

Next Step

Conditions classified a single record. Processing the entire measurement list requires repetition. The next lesson covers loop forms: the counted loop, the conditional loop, and two different collection loops. The difference between the two collection loops — one gives keys, the other gives values — produces unexpected results on arrays.

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ Esc navigate · open · close