Skip to main content

JS If & Switch

Deep dive into the two pillars of JavaScript flow control

If Statements

The most popular way of handling conditional logic is with the if statement. It is universal, flexible, and easy to understand. By evaluating a condition, it allows your script to either execute or omit part of the code.

Create a segment of customers that made more than two purchases
for (let customer of customers) {
if (customer.purchases > 2) {
marketingSegment.push(customer.email);
}
}

Basic if can be extended by adding optional else if for an additional condition with the different outcome or optional else for all scenarios not caught by above conditions.

Create multiple segments for different levels of customers
for (let customer of customers) {
if (customer.purchases > 10) {
goldCustomerSegment.push(customer.email);
} else if (customer.purchases > 5) {
silverCustomerSegment.push(customer.email);
} else {
bronzeCustomerSegment.push(customer.email);
}
}

And, Or, Brackets

The if statement is even more powerful if you enhance your conditions with the ORs (||), ANDs (&&) and brackets:

Split customers into two segments depending on a condition group
for (let customer of customers) {
if (customer.purchases <=2 || customer.lastPurchaseDate <= new Date('2019-12-31')) {
reengagementCampaignSegment.push(customer);
} else if (customer.purchases > 2 && customer.lastPurchaseDate > new Date('2019-12-31')) {
upsellCampaignSegment.push(customer);
}
}

Boolean evaluation

You can use boolean values of variables/methods/functions to omit the operator in your condition and make the code more readable.

If the customer has domain of your competiton, add him to blocklist
for (let customer of customers) {
const competitionUser = customer.email.includes('@competition.com');
if (competitionUser) { // if comptetitionUser is true, block will be exectuted
blocklist.push(customer);
}
}

Flip Booleans with Bang

Bang symbol (!) can be used to flip the value of a boolean:

If the customer does not have competition domain in email, add him to campaign
for (let customer of customers) {
const competitionUser = customer.email.includes('@competition.com');
if (!competitionUser) { // if not competition user, execute content
campaignSegment.push(customer);
}
}

Bang not only functions as a NOT operator but also changes truthy and falsy values into an (opposite) boolean.

Falsy values in JavaScript are: false, 0, empty string "", null, undefined, NaN. All other possible values are considered truthy.

This is very useful, as it allows you to leverage boolean evaluation on truthy values:

Applies either personalized name or default value
for (let customer of customers) {
let helloPersonalization;
if (customer.firstName) { // if customer.firstName has characters, it is truthy
helloPersonalization = customer.firstName;
} else if (!customer.firstName) { // if it does not have any characterrs, it will be falsy
helloPersonalization = 'Valued Customer';
}
}

To make it clear - above code is very "dirty" and can be written much better (for example without else if by applying default value on variable initialization). You will find an example of how to write it better later.

You Should Know

You can level up the use of this feature by leveraging double bang !! to convert truthy/falsy value into an (appropriate) boolean.

If optInDate has any value (is not empty) the isOptedIn variable will evaluate to true
const isOptedIn = !!optInDate;

If Shorthand

For simple, one-line if statements, there is also a one-line shorthand:

If the customer is opted in, send an email
if (isOptedIn) sendEmail(emailAddress, emailID);

You could probably use simple if statements for the whole logic of your code. But you shouldn't. There are some interesting and useful options worth checking out.


Ternary

If a simple if statement has only two possible outcomes depending on a condition, ternary is more straightforward and readable alternative. Based on previous example, instead of:

Dirty if statement using basic 'if'
for (let customer of customers) {
let helloPersonalization = 'Hello ';
if (customer.firstName) {
helloPersonalization += customer.firstName;
} else if (!customer.firstName) {
helloPersonalization += 'Valued Customer';
}
}

we can use a clean ternary:

Same logic changed to a clean ternary
for (let customer of customers) {
let helloPersonalization = customer.firstName ? 'Hello ' + customer.firstName : 'Hello Valued Customer';
}

Instead of 6 lines of code, we have 1. Awesome! But how does it work? The ternary structure looks like this: variable = condition ? valueIfTrue : valueIfFalse;. So in the example above, if the customer.firstName is not empty (is truthy), it will be pushed as the value of helloPersonalization. If it is empty, the default value will be assigned instead.

You Should Know

The ternary has more uses not than just the standard if statement. It is awesome text customization with interpolation:

Fill in the sentence with different words depending on boolean value of isOptedIn
const optInStatusMessage = `You are ${isOptedIn ? 'opted in' : 'not opted in'}`;

Ternaries are not limited to variables and strings. They can also run functions:

If isLoggedIn is false, the redirectToLogInPage function will be executed
!isLoggedIn ? redirectToLogInPage() : null;

Shortcircuiting

We already covered using OR || + AND && operators. But by using them correctly, you can optimize the speed of your scripts greatly.

Shortcircuiting OR

OR evaluates to true if at least one value is equal to true.

If the left side of the OR evaluates to true, we know for sure that the whole statement is true. Checking the value of the right side is not needed. And JavaScript knows this too.

Thanks to it, if we want to use an OR statement and we suspect that one side is much faster than the other, we should use it on the left side.

If last purchase was before 2020 or a very complex check requiring calls to eCommerce API evaluates to false, filter out the customer from the campaign
for (let customer of customers) {
if (customer.lastPurchaseDate < new Date('2019-12-31') || complexRequestToEcommerceAPI() === false) {
exclusionSegment.push(customer)
}
}

Left side in the above example is a straightforward and quick check, as all parts of the condition are already within the script. The right side, however, might take seconds to get the data from other system and calculate the value. If the lastPurchaseDate is before our threshold, we don't have to waste time and API calls. A win for us, and a win for the customer waiting for the script to finish.

Shortcircuiting AND

Similar logic can be applied to AND operator. && evaluates to true only if both sides are true. If we have a more straightforward condition or we suspect it might frequently evaluate to false, we should put it on the left side. If it ends up being falsy, JavaScript won't be checking the right side of the AND operator.

If the email provided for login is in correct format, check if password has required length. Once validated, check if this login and password are matching pair for a user. Only then consider the login to be valid
if (isValidEmail(login) && isValidPassword(password) && isValidPair(email, password)) {
const isLoggedIn = true;
}

In the above example, we are doing multiple tests ordered from the easiest to the hardest. Thanks to it, if the login is not in the correct format for an email address, we won't have even to check the password or query our encrypted database with a hashed version of the password.

You Should Know

Using shortcircuit is a quite popular pattern, especially for managing user interface components:

If the user is not an admin, shortcircuit and don't render the AdminBar component
isAdmin && showAdminBar()

Switch Statement

Sometimes you have many options for a single condition. You could write it with a simple if, but the switch might be much more readable than a long list of else if statements with nearly identical conditions.

Return the error type based on the code
function errorDescription(error) {
switch (error.code) {
case 400:
return 'Bad Request';
case 401:
return 'Unauthorized';
case 403:
return 'Forbidden';
case 404:
return 'Not Found'
default:
return 'Unknown Error';
}
}

Some things to remember when working with a switch:

  • If multiple cases fulfil the condition, a switch will execute the first from the top.
  • You can assign multiple cases to the same code block:
Return either sum or difference of two values (sum by default)
let outcome;
switch (a, operation, b) {
default:
case '+':
case 'plus':
outcome = a + b;
break;
case '-':
case 'minus':
outcome = a - b;
break;
}
  • Use either break statement to end each case or use the return statement if in function. Otherwise, the switch will also execute all below cases until it encounters one of the above keywords (or hits the last scenario). Of course, there might be some edge scenarios where you want this exact behaviour to happen.
  • Always use default statement, even if you believe it will never be triggered (not required, but best practice). Use it to handle the scenario you haven't considered.
  • Cases in a switch are using strict comparison (===) for evaluation, so the provided value must match the case not only by value but also by type. A string value of '0' won't trigger an integer 0 case.
You Should Know

By default, the switch statement is a single block for the scope. If you, however, want to declare variables of the same name in different cases, you can do it by adding parentheses:

Despite 'outcome' variable being initialized twice with 'let', it will not drop an error because of two different block scopes
switch (a, operation, b) {
default:
case '+':
case 'plus': {
let outcome = a + b;
break;
}
case '-':
case 'minus': {
let outcome = a - b;
break;
}
}