WasiLearn Code
JavaScript · Making decisions and repeating

if, else if, else, and truthiness

A program that always does the same thing is a very expensive way to print a fixed message. The moment it has to react — pass or fail, open or closed, enough seats or not — you need a way to run one piece of code and skip another.

let marks = 44;

if (marks >= 50) {
  console.log("Pass");
} else {
  console.log("Fail");
}
output
Fail

The condition in the brackets produces a boolean, exactly as in the equality lesson. If it is true, the first block runs. Otherwise the else block does. Never both.

else if chains, and why order decides everything

For more than two outcomes you add else if between them. JavaScript checks each condition in order and stops at the first one that is true.

let examMarks = 72;

if (examMarks >= 80) {
  console.log("A");
} else if (examMarks >= 65) {
  console.log("B");
} else if (examMarks >= 50) {
  console.log("C");
} else {
  console.log("Not passed");
}
output
B

72 is not 80 or more, so the first test fails. It is 65 or more, so the second succeeds, B prints, and every remaining branch is skipped without being looked at.

That "stops at the first true one" behaviour is the whole reason order matters, and getting it backwards produces a bug that never crashes:

let topMarks = 91;

if (topMarks >= 50) {
  console.log("C");
} else if (topMarks >= 80) {
  console.log("A");
}
output
C

91 deserves an A and receives a C. The >= 80 line can never run, because anything that reaches 80 already passed the >= 50 test above it. Write threshold chains from the most demanding condition down to the least, always.

The braces are not decoration

You are allowed to leave the curly braces off when the branch is a single statement. It reads fine and it sets a trap.

let raining = false;

if (raining)
  console.log("Take the bus.");
  console.log("Carry an umbrella.");
output
Carry an umbrella.

The indentation says both lines belong to the if. JavaScript disagrees: without braces only the first statement is controlled, and the second one runs unconditionally. It rained on nobody and the umbrella advice came out anyway.

This bug survives code review because the code looks correct. Put the braces on every if, including one-liners, and it cannot happen.

Truthy and falsy

The condition does not have to be a boolean. Give if any value and JavaScript converts it to true or false first. Values that convert to false are called falsy, and there are only a handful of them.

console.log(Boolean(0));
console.log(Boolean(""));
console.log(Boolean(null));
console.log(Boolean(undefined));
console.log(Boolean(NaN));
console.log(Boolean(false));
output
false
false
false
false
false
false

That is the complete list for everyday purposes: zero, the empty string, null, undefined, NaN and false itself. Everything else is truthy — every non-empty string, every non-zero number including negatives, every array, every object.

console.log(Boolean("0"));
console.log(Boolean("false"));
console.log(Boolean(-1));
console.log(Boolean(" "));
console.log(Boolean([]));
output
true
true
true
true
true

The string "false" is truthy, because it is a five-character string and JavaScript is not reading English. A single space is truthy for the same reason. An empty array is truthy, even though an empty string is not.

if (count) does not ask whether count exists

Here is the mistake, and it is a good one because the wrong version works almost all the time.

You want to show a score only when there is a score to show, so you write if (goalsScored). It reads like "if there is a goals figure". It is not what it means.

let goalsScored = 0;

if (goalsScored) {
  console.log("Bilal scored " + goalsScored + " goals.");
} else {
  console.log("No score recorded for Bilal.");
}
output
No score recorded for Bilal.

Bilal played. His score was recorded. It was zero, and zero is falsy, so the program announced that no score exists. Test it with 2 goals and it works. Test it with 5 and it works. The only failing case is the one nobody thinks to try, and it will reach production.

The same applies to the empty string. A comment field the user deliberately left blank is a real answer, and if (comment) throws it away as if the field were never there.

if (value) asks: is this value truthy? It does not ask whether the value exists, whether it was set, or whether it is meaningful. When zero and empty string are legitimate data — counts, scores, prices, totals, quantities in stock — those are three different questions and you must pick the right one.

let goalsRecorded = 0;

if (goalsRecorded !== undefined) {
  console.log("Bilal scored " + goalsRecorded + " goals.");
} else {
  console.log("No score recorded for Bilal.");
}
output
Bilal scored 0 goals.

!== undefined asks the question you meant: has this been set at all? If the missing value might be null as well, goalsRecorded != null covers both, which is the one loose-equality idiom worth keeping.

The bare truthiness test is still fine when falsy really does mean absent — a name, a search term, an address. Use it knowingly, not by habit.

The ternary operator

When both branches do the same kind of thing and differ only in a value, a full if block is four lines of ceremony for one decision. The ternary operator compresses it.

let finalMarks = 44;
let result = finalMarks >= 50 ? "Pass" : "Fail";

console.log(result);
output
Fail

Read it as a question and two answers: condition, then ?, then the value if true, then :, then the value if false. Unlike if, it produces a value, so it can go straight into a variable or inside a template literal from the strings lesson.

let cupsOrdered = 1;

console.log(`You ordered ${cupsOrdered} ${cupsOrdered === 1 ? "cup" : "cups"}.`);
output
You ordered 1 cup.

That is the ternary at its best — one small choice inside a sentence, where an if block would force you to build the string in pieces.

It is at its worst when nested. A ternary inside a ternary inside a ternary is a grading chain written to be difficult. If your decision has more than two outcomes, use else if and let it take the space.

Conditions inside conditions

Branches can contain branches, which lets you narrow a decision in stages.

let hour = 15;

if (hour >= 8) {
  if (hour < 17) {
    console.log("The canteen is open.");
  } else {
    console.log("The canteen has closed for the day.");
  }
} else {
  console.log("The canteen has not opened yet.");
}
output
The canteen is open.

Two levels is usually readable. Three is a signal to stop and rethink — either combine the conditions with the logical operators, or handle the simple cases first and return early. Deep nesting is where logic goes to hide.

Handle the impossible cases first

The habit that pays off longest: at the top of any decision, deal with the values that should not be there before you deal with the ones that should.

let enteredScore = Number("not a number");

if (Number.isNaN(enteredScore)) {
  console.log("That is not a valid score.");
} else if (enteredScore >= 50) {
  console.log("Pass");
} else {
  console.log("Fail");
}
output
That is not a valid score.

Without that first branch, NaN >= 50 is false, the chain falls through to else, and a typing mistake gets reported as a failed exam. Every comparison involving NaN is false, as the numbers lesson explains, so bad input does not announce itself — it quietly takes the last branch. Check for it before you trust the number, and the rest of the chain only ever sees real values.

Prefer learning with a teacher?

WasiLearn Academy runs small-group classes covering this material, online and in Karachi.

See the classes