The Switch/Case Statement in JavaScript
The switch
statement evaluates an expression, and executes a block of code based on which case
the expression evaluated to.
const hero = 'Batman';
let sidekick;
switch (hero) {
case 'Batman':
sidekick = 'Robin';
break;
case 'Aquaman':
sidekick = 'Aqualad';
break;
case 'Superman':
sidekick = 'Jimmy Olsen';
break;
default:
throw new Error('Unknown hero');
}
sidekick; // 'Robin'
Make sure you don't forget the break
statement at the end of a block!
If you don't put a break
statement at the end of a case
block,
JavaScript will "fall through" to the next case
.
const hero = 'Batman';
let sidekick;
switch (hero) {
case 'Batman':
sidekick = 'Robin';
// Unless there's a `break`, JavaScript will execute the next
// `case` block.
// break;
case 'Aquaman':
sidekick = 'Aqualad';
break;
case 'Superman':
sidekick = 'Jimmy Olsen';
break;
default:
throw new Error('Unknown hero');
}
// JavaScript executed both the 'Batman' and 'Aquaman' blocks,
// so you get the wrong `sidekick`.
sidekick; // 'Aqualad'
There are some benefits to this behavior. You can execute one block
for multiple case
statements. For example:
const sidekick = 'Nightwing';
let hero;
switch (sidekick) {
// The 'Robin' and 'Nightwing' cases are "fallthrough" `case`
// statements. They execute the same code block as the 'Bluebird'
// case.
case 'Robin':
case 'Nightwing':
case 'Bluebird':
hero = 'Batman';
break;
case 'Aqualad':
case 'Tempest':
hero = 'Aquaman';
break;
default:
throw new Error('Unknown sidekick');
}
hero; // 'Batman'
Equality Check
The switch
statement evaluates the given expression once, and compares
it against each case
expression using strict equality. The below if
statement
is functionally equivalent to the first example:
const hero = 'Batman';
let sidekick;
if (hero === 'Batman') {
sidekick = 'Robin';
} else if (hero === 'Aquaman') {
sidekick = 'Aqualad';
} else if (hero === 'Superman') {
sidekick = 'Jimmy Olsen';
} else {
throw new Error('Unknown hero');
}
sidekick; // 'Robin'
Because the switch
statement uses strict equality, you're responsible
for doing type conversions if you want to compare objects, like dates
or MongoDB ObjectIds.
const date = new Date('2020/07/04');
let holiday;
const goodFriday = new Date('2020/04/10');
const independenceDay = new Date('2020/07/04');
const christmas = new Date('2020/12/25');
// Strict equality means two dates aren't equal unless they're
// the same object reference.
date === independenceDay; // false
// `date` is an object, so you need to make sure you convert the
// date to a number using `getTime()`. Otherwise none of the
// cases will hit.
switch (date.getTime()) {
case goodFriday.getTime():
holiday = 'Good Friday';
break;
case independenceDay.getTime():
holiday = 'Independence Day';
break;
case christmas.getTime():
holiday = 'Christmas';
break;
}
holiday; // 'Independence Day'
Alternatives
Unless you're using fallthrough case
statements, you can use if
as a
replacement for switch/case
. Another alternative is defining an object
or map
that contains functions to execute based on case
:
const hero = 'Batman';
let sidekick;
const obj = {
'Batman': () => { sidekick = 'Robin'; },
'Aquaman': () => { sidekick = 'Aqualad'; },
'Superman': () => { sidekick = 'Jimmy Olsen'; }
};
// Make sure to use `hasOwnProperty()` if you're using an object,
// otherwise 'constructor' would be a valid `hero`.
if (obj.hasOwnProperty(hero)) {
obj[hero]();
}
sidekick; // 'Robin'
The advantage of using an object conditional is you can build up the object
programatically. If your switch
statement is getting a little too repetitive,
you can instead build up an object conditional with a for
loop.
Recommended Use
The switch
statement comes with a lot of gotchas, like unintentionally
falling through to the next case
statement. ESLint has a no-fallthrough
rule that can help you catch this at the linter level.
However, there's rarely a reason to use switch
as opposed to if/else if
or
objects - because switch
is less common than if
, fewer developers are
comfortable with the semantics of switch
.