Mert Özen Further With Every Line
Frontend JavaScript Basics — #06

JavaScript Conditionals: if/else, the Ternary Operator and switch

Mert Özen Nov 3, 2026 8 min 5 views
JavaScript Conditionals: if/else, the Ternary Operator and switch

We use examples to cover if/else if/else chains, the ternary operator, fall-through and break in switch, truthy/falsy traps in conditions, the early return idea and writing readable conditions.

Version note: The code in this post targets ES2026 and current browsers (Chrome, Edge, Firefox, Safari).

Predict First

A small piece of code that finds the day of the week from its number:

const day = 2;
switch (day) {
  case 1:
    console.log("Monday");
  case 2:
    console.log("Tuesday");
  case 3:
    console.log("Wednesday");
  default:
    console.log("Unknown");
}

What does this code print to the console? Just "Tuesday"? Make a guess before you keep reading. We'll give the answer when we talk about how switch moves through its body.

if: A Fork in the Road

All the code we've written so far ran from top to bottom, executing every line. Real programs make decisions all the time: if the user is logged in, show the profile; if the cart is empty, show a warning; if the password is too short, reject it. The basic tool for this is if. Paste this into your browser's console and try it:

const temperature = 32;
if (temperature > 30) {
  console.log("It's very hot today, don't forget to drink water.");
}
console.log("Weather checked.");

The expression inside the parentheses is the condition. The engine evaluates it; if the result is truthy, it enters the curly braces, otherwise it skips the block and carries on. The last line doesn't depend on the condition; it runs in every case. Set temperature to 20 and try again, and you'll see the first message disappear.

The block scope we saw earlier applies here too: a variable you declare with let or const inside an if block can't be seen from outside the block.

else and else if: More Than One Path

If you also want to do something when the condition doesn't hold, you add else. When there are more than two options, else if goes in between:

const score = 72;
if (score >= 90) {
  console.log("A");
} else if (score >= 70) {
  console.log("B");
} else if (score >= 50) {
  console.log("C");
} else {
  console.log("Fail");
}

The output is B. The engine tries the conditions one by one from top to bottom and runs the block of the first one that holds; it doesn't even look at the rest. That's why order matters. If you wrote the conditions in reverse and checked score >= 50 first, a student with 92 would also get a "C," because 92 is greater than 50 too and that condition would match first.

Think of exit signs on a highway. At each sign you ask "is this my exit?"; at the first "yes" you leave the road and never see the following signs. else is the end of the road: you get there if you didn't take any of the exits.

Truthy and Falsy in Conditions

You don't have to put a comparison inside the parentheses of an if. The truthy/falsy rule we saw earlier kicks in here: whatever value is in the parentheses, the engine interprets it as truthy or falsy.

const userName = "";
if (userName) {
  console.log("Hello " + userName);
} else {
  console.log("Please enter your name.");
}

The empty string is falsy, so you'll see "Please enter your name." This short form is very common and readable, but if you don't keep the falsy list in mind, it can mislead you:

const discount = 0;
if (discount) {
  console.log("Discount: " + discount + "%");
} else {
  console.log("No discount info.");
}

Here 0 is valid information; it means "no discount." But since 0 is falsy, the code says "no info." Where a value can be zero, spell out what you mean, for example if (typeof discount === "number"). The opposite is a trap too: an empty array is truthy, so if (cart) goes inside even when the cart is empty. If you want to ask whether the array has anything in it, write if (cart.length > 0); we'll cover length in detail in the post on arrays.

Ternary: A One-Line Decision

Sometimes you just want to pick a value based on a condition. Instead of a four-line if/else, you can use the ternary operator for that:

const age = 20;
const ageGroup = age >= 18 ? "adult" : "child";
console.log(ageGroup);

Read it like this: "is the condition true? If so, this; if not, that." The left of the question mark is the condition, and the two sides of the colon are the options. The ternary is the only operator in JavaScript with three parts, which is where its name comes from. Its key difference from if is that it's an expression, meaning it produces a value; that's why you can assign it straight to a variable or write it inside a console.log.

The ternary is ideal for a quick choice between two options. Once you start nesting it, though, readability drops fast:

const degrees = 25;
const feel = degrees > 30 ? "hot" : degrees > 15 ? "mild" : "cold";
console.log(feel);

It works and prints mild, but the reader has to go over the line twice. With three or more options, if/else if is the clearer choice.

switch: One Value, Many Options

If you're comparing the same variable against a series of fixed values, switch offers a tidier layout:

const fruit = "apple";
switch (fruit) {
  case "apple":
    console.log("Apples are $3");
    break;
  case "banana":
    console.log("Bananas are $5");
    break;
  default:
    console.log("We don't have that fruit.");
}

The engine compares the value in the parentheses with each case in turn. That comparison is done with ===, so the type has to match too. If no match is found, it goes to default; default isn't required, but writing it is a good habit that shows you've thought about the "none of the above" case.

Now let's see what break is for, and get to the opening question. The answer: you'll see "Tuesday," "Wednesday" and "Unknown," one under the other. When switch finds the matching case, it enters there and starts flowing downward. It doesn't check the case labels it passes; it runs every line until it sees a break or reaches the end of the switch. This is called fall-through.

Think of the case labels as entry points on a slide. The case decides where you get on, but once you start sliding, you keep going down until a break stops you. The prediction code has no break at all, so code that got on at point 2 slid all the way to the bottom.

Fall-through isn't always a mistake. It's used on purpose when you want several values to produce the same result:

const dayName = "Saturday";
switch (dayName) {
  case "Saturday":
  case "Sunday":
    console.log("Weekend");
    break;
  default:
    console.log("Weekday");
}

"Saturday" matches, and since there are no lines under it, it flows into the "Sunday" block and prints "Weekend." So when should you use switch, and when if? If you're comparing one value against fixed options for an exact match, switch; if ranges, greater-than/less-than, or several variables are involved, if.

Early Exits and Readable Conditions

As conditions nest, code drifts to the right and gets harder to read. The most effective cure is the early exit: handle the cases that shouldn't happen first and finish right away. We see this most clearly with functions. We'll cover functions in detail in upcoming posts; for now, read return as "hand back the result and leave the function":

function calculateDiscount(amount, isMember) {
  if (amount <= 0) {
    return 0;
  }
  if (!isMember) {
    return amount;
  }
  return amount * 0.9;
}
console.log(calculateDiscount(200, true));
console.log(calculateDiscount(200, false));
console.log(calculateDiscount(-5, true));

The output is 180, 200 and 0. We filtered out the invalid amount first, then non-members, and left the real work for the end. Writing the same logic with nested if/else would take three levels of indentation and two else branches. This pattern is also called a guard clause: the guard at the door turns away whoever doesn't qualify, and only the real work is left inside.

A few more habits for readability. Pull a long condition into a variable with a meaningful name. Instead of if (age >= 18 && hasLicense && !isBanned), first write const canDrive = age >= 18 && hasLicense && !isBanned;, then say if (canDrive). Phrase conditions positively whenever you can; double negatives like if (!isNotClosed) wear the reader out. And don't drop the curly braces even for one-line blocks; a second line added later silently ends up outside the block.

Common Pitfalls

Assigning instead of comparing. If you write if (x = 5), 5 is assigned to x, and since 5 is truthy, the condition always holds. Use === for comparisons.

Trying to shorten things with ||. if (color === "red" || "blue") doesn't ask "is the color red or blue?" The "blue" on the right is a string on its own, and since it isn't empty, it's truthy; the condition holds for every color. The correct way is to write the comparison on both sides: color === "red" || color === "blue".

Forgetting the type in a switch. Because switch uses ===, case 2: inside switch ("2") doesn't match. Values from forms are usually strings; make the types match before comparing.

Putting a semicolon after if. If you write if (false); { ... }, the semicolon becomes the if's body as an empty statement, and the block in curly braces runs every time, regardless of the condition.

Declaring the same name in different cases. The whole switch is a single block. If you write let message in two different cases, you get SyntaxError: Identifier 'message' has already been declared. Wrapping each case body in its own curly braces solves it.

A Small Experiment

★☆☆ Declare an hour variable (between 0 and 23). Build an if/else if/else chain that prints "Good morning," "Good afternoon" or "Good evening" depending on the hour. Check which message the boundary values (12, 18) fall into.

★★☆ Predict the output before running it, then try it:

const choice = "2";
switch (choice) {
  case 1:
    console.log("one");
    break;
  case 2:
    console.log("two");
  case "2":
    console.log("text two");
  default:
    console.log("default");
}

★★★ Write a shippingFee(amount, city) function that calculates a shipping fee: return 0 if the amount is 0 or less, make shipping free if the amount is 500 or more, return 40 if the city is "Istanbul" and 60 for other cities. Write it first with nested if/else, then with early return, and put the two versions side by side to decide which reads more easily.

Conditions choose which path the code takes. But sometimes you need to walk the same path over and over: printing every product in a list, increasing a number until it reaches a target. In the next post we move on to loops: for, while, for...of, for...in and the infinite loop trap.