switch Keyword

Description

A switch statement first evaluates its expression. It then looks for the first case clause whose expression evaluates to the same value as the result of the input expression (using the strict comparison, ===) and transfers control to that clause, executing all statements following that clause.

The clause values are only evaluated when necessary - if a match is already found, subsequent case clause values will not be evaluated, even when they will be visited by fall-through.

switch (undefined) {
  case console.log(1):
  case console.log(2):
}
// Only logs 1

If no matching case clause is found, the program looks for the optional default clause, and if found, transfers control to that clause, executing statements following that clause. If no default clause is found, the program continues execution at the statement following the end of switch. By convention, the default clause is the last clause, but it does not need to be so. A switch statement may only have one default clause; multiple default clauses will result in a SyntaxError.


Breaking and fall-through

You can use the break statement within a switch statement's body to break out early, often when all statements between two case clauses have been executed. Execution will continue at the first statement following switch.

If break is omitted, execution will proceed to the next case clause, even to the default clause, regardless of whether the value of that clause matches. This behavior is called "fall-through".

const foo = 0;
switch (foo) {
  case -1:
    console.log('negative 1');
    break;
  case 0: // Value of foo matches this criteria; execution starts from here
    console.log(0);
    // Forgotten break! Execution falls through
  case 1: // no break statement in 'case 0:' so this case will run as well
    console.log(1);
    break; // Break encountered; will not continue into 'case 2:'
  case 2:
    console.log(2);
    break;
  default:
    console.log('default');
}
// Logs "0" and "1"

You can use other control-flow statements to replace break, such as a return statement.


Lexical scoping

The case and default clauses are like labels: they indicate possible places that control flow may jump to. However, they don't create lexical scopes themselves (neither do they automatically break out - as demonstrated above). For example:

const action = 'say_hello';
switch (action) {
  case 'say_hello':
    const message = 'hello';
    console.log(message);
    break;
  case 'say_hi':
    const message = 'hi';
    console.log(message);
    break;
  default:
    console.log('Empty action received.');
}

This example will output the error "Uncaught SyntaxError: Identifier 'message' has already been declared", because the first const message = 'hello'; conflicts with the second const message = 'hi'; declaration, even when they're within their own separate case clauses. Ultimately, this is due to both const declarations being within the same block scope created by the switch body.

To fix this, whenever you need to use let or const declarations in a case clause, wrap it in a block.

const action = 'say_hello';
switch (action) {
  case 'say_hello': { // added brackets
    const message = 'hello';
    console.log(message);
    break;
  } // added brackets
  case 'say_hi': { // added brackets
    const message = 'hi';
    console.log(message);
    break;
  } // added brackets
  default: { // added brackets
    console.log('Empty action received.');
  } // added brackets
}

This code will now output hello in the console as it should, without any errors.