Else If in JavaScript: Syntax, Examples, and Pitfalls
You have a score of 92 and three possible labels. The order of your conditions decides whether JavaScript calls it a distinction, a pass, or something else entirely.
In JavaScript, write
else ifas two words to test conditions from top to bottom, run the first truthy branch, and skip the rest of the chain.
JavaScript Else If Syntax
An else if chain starts with one if, continues with zero or more else if clauses, and may finish with one else. Each condition goes inside parentheses, and each branch is a statement. These examples use recommended braces, even though JavaScript permits a single statement without them:
function classifyScore(score) {
if (score >= 90) {
return "distinction";
} else if (score >= 75) {
return "merit";
} else if (score >= 60) {
return "pass";
} else {
return "retry";
}
}
console.log(classifyScore(82));
merit
The score fails score >= 90, passes score >= 75, and returns "merit". The two later branches do not run.
JavaScript has no one-word elseif keyword and no elif keyword. Write else if with a space. Syntactically, this works because the statement after else is another if statement, although developers normally read the connected structure as one chain.
The final else is optional. Use it when every remaining input belongs in one fallback branch. Leave it out when doing nothing is a valid result:
function warnAboutScore(score) {
if (score < 0) {
return "score is below zero";
} else if (score > 100) {
return "score is above 100";
}
return "score is in range";
}
console.log(warnAboutScore(74));
score is in range
Both explicit conditions are false, so execution continues after the chain. Conditional branching: if, ’?’ covers the wider if, else, and conditional-operator model.
How an Else If Chain Runs
An else if chain follows one rule: the first truthy condition wins.
JavaScript begins at the first if. If that condition is falsy, it moves to the next else if; if the condition is truthy, JavaScript runs that branch and skips every remaining clause in the chain.
A branch tracer makes those decisions visible. This version requires Node.js, which makes command-line arguments available through process.argv. Save the program as branch-tracer.js, then pass a score with a command such as node branch-tracer.js 92:
function traceScore(score) {
const checks = [
{ test: "score >= 90", matches: () => score >= 90, label: "distinction" },
{ test: "score >= 75", matches: () => score >= 75, label: "merit" },
{ test: "score >= 60", matches: () => score >= 60, label: "pass" },
];
let selected = false;
for (const check of checks) {
if (selected) {
console.log(`skipped ${check.test}`);
} else if (check.matches()) {
console.log(`tested ${check.test}: truthy`);
console.log(`selected: ${check.label}`);
selected = true;
} else {
console.log(`tested ${check.test}: falsy`);
}
}
if (selected) {
console.log("skipped else");
} else {
console.log("selected: retry");
}
}
const argument = process.argv[2];
const score = argument === undefined ? 92 : Number(argument);
if (!Number.isFinite(score)) {
console.log("enter a numeric score");
} else {
traceScore(score);
}
tested score >= 90: truthy
selected: distinction
skipped score >= 75
skipped score >= 60
skipped else
The default score, 92, satisfies the first condition. The tracer marks that branch as selected and every later choice as skipped. Change the command-line value to 82, and the first test becomes falsy before score >= 75 selects "merit".
This stopping rule applies to the whole connected chain. It does not matter whether another condition farther down would also be truthy. Once one branch runs, selection is over.
That distinction matters when conditions overlap.
Condition Order Changes the Result
Range conditions often overlap. A score of 92 satisfies score >= 60, score >= 75, and score >= 90 at the same time, so their order determines which label wins.
Put the broad passing condition first and the higher branches become unreachable for passing scores:
function classifyScoreWrong(score) {
if (score >= 60) {
return "pass";
} else if (score >= 75) {
return "merit";
} else if (score >= 90) {
return "distinction";
} else {
return "retry";
}
}
console.log(classifyScoreWrong(92));
console.log(classifyScoreWrong(82));
pass
pass
Both scores match score >= 60, so JavaScript returns "pass" without testing either higher threshold. The syntax is valid. The classification is not.
For these overlapping >= thresholds, place the highest threshold first and work downward:
function classifyScore(score) {
if (score >= 90) {
return "distinction";
} else if (score >= 75) {
return "merit";
} else if (score >= 60) {
return "pass";
} else {
return "retry";
}
}
console.log(classifyScore(92));
console.log(classifyScore(82));
console.log(classifyScore(64));
console.log(classifyScore(48));
distinction
merit
pass
retry
Each condition now describes the highest remaining category. By the time JavaScript tests score >= 75, it already knows the score is below 90. By the time it reaches score >= 60, it already knows the score is below 75.
High-to-low ordering is required for this particular pattern because the >= ranges overlap. It is not a universal rule for every chain. Conditions that do not overlap can use any order that preserves the intended result, while conditions with side effects deserve a redesign instead of clever ordering.
The general rule is narrower: when several conditions can match the same input, put the branch that should win first.
Comparison details such as >=, strict equality, and string ordering are covered in Comparisons.
What Counts as True or False
An if condition does not need to produce the literal Boolean value true. JavaScript converts the condition to a Boolean, then chooses a branch from that result. This use of a value is called a Boolean context.
The complete falsy set is short:
falseundefinednullNaN- positive and negative numeric zero, including
0and-0 0n- the empty string,
"" - the legacy browser value
document.all
Every other value is truthy. That includes some values that can look empty:
const values = [
["nonempty string", "false"],
["empty array", []],
["empty object", {}],
["zero", 0],
["empty string", ""],
];
for (const [name, value] of values) {
if (value) {
console.log(`${name}: truthy`);
} else {
console.log(`${name}: falsy`);
}
}
nonempty string: truthy
empty array: truthy
empty object: truthy
zero: falsy
empty string: falsy
The string "false" contains characters, so it is truthy. Empty arrays and empty ordinary objects are still objects, and objects are truthy in Boolean contexts.
This catches form handling code. A text field containing "0" is truthy because it contains one character, while the number 0 is falsy:
function describeGuests(guests) {
if (guests) {
return "guest value is truthy";
} else {
return "guest value is falsy";
}
}
console.log(describeGuests("0"));
console.log(describeGuests(0));
guest value is truthy
guest value is falsy
When you need a particular meaning, test it directly. guests === 0, name.length === 0, and items.length > 0 state three different intentions. A bare truthiness check folds those meanings together.
Logical operators explains how the same Boolean conversion affects &&, ||, and !.
Else If Versus Separate If Statements
An else if chain performs mutually exclusive selection: at most one branch runs. Separate if statements perform independent tests: each condition is tested if control reaches it, and multiple truthy bodies can run unless an earlier body redirects control flow.
Use the same score, 92, in both structures to expose the difference:
const score = 92;
if (score >= 90) {
console.log("chain: distinction");
} else if (score >= 75) {
console.log("chain: merit");
} else if (score >= 60) {
console.log("chain: pass");
}
if (score >= 60) {
console.log("independent: passed");
}
if (score >= 75) {
console.log("independent: merit threshold reached");
}
if (score >= 90) {
console.log("independent: distinction threshold reached");
}
chain: distinction
independent: passed
independent: merit threshold reached
independent: distinction threshold reached
The chain chooses one label. The standalone statements report all milestones the score reached.
Neither structure replaces the other. If a customer can receive one shipping category, use a chain. If the same order can require an address check, an age check, and a stock check, use independent statements because several actions may apply.
Say you accidentally connect independent validations with else if. A failed address check can prevent the age check from running, even though both errors need reporting. The code still looks orderly, but it answers the wrong question.
Ask whether branches compete for one result or represent separate facts. One result points to else if; separate facts point to separate if statements.
Common Else If Mistakes
The first mistake happens before the program runs: elseif and elif are not JavaScript syntax. The valid spelling is else if.
Braces cause the subtler mistakes. JavaScript permits a single unbraced statement after if or else, but an else attaches to the nearest eligible if. Indentation does not change that rule:
const accountActive = true;
const emailVerified = false;
if (accountActive)
if (emailVerified)
console.log("open dashboard");
else
console.log("verify email");
verify email
The else belongs to if (emailVerified), not if (accountActive). Braces make that ownership visible:
const accountActive = true;
const emailVerified = false;
if (accountActive) {
if (emailVerified) {
console.log("open dashboard");
} else {
console.log("verify email");
}
}
verify email
The output stays the same, but the structure no longer depends on indentation. Prefer braces in every branch. Code structure covers blocks and statement boundaries in more detail.
An assignment inside a condition is another quiet bug:
let status = "draft";
if (status = "published") {
console.log(status);
}
published
status = "published" assigns a nonempty string, and that string is truthy. Use status === "published" when you mean comparison.
Other failures come from the conditions themselves. A broad branch can make a narrower one unreachable, adjacent ranges can leave a boundary uncovered, and duplicated conditions can leave the later branch permanently unused.
Test inputs at every boundary and on both sides of it. This compact table checks the score chain:
| Input | >= 90 | >= 75 | >= 60 | Expected branch | Boundary being checked |
|---|---|---|---|---|---|
59 | false | false | false | retry | immediately below pass |
60 | false | false | true | pass | pass begins |
74 | false | false | true | pass | immediately below merit |
75 | false | true | true | merit | merit begins |
89 | false | true | true | merit | immediately below distinction |
90 | true | true | true | distinction | distinction begins |
If 90 returns "pass", ordering is wrong. If 75 returns no label, a boundary has a gap. If no input reaches "distinction", that branch is unreachable.
For a long chain, first name complicated predicates, then extract the decision into a function and test its boundaries. If the chain maps exact values, switch may fit. If it expresses ranges, an ordered else if chain often remains the clearest shape. The Coding style guide takes the same clarity-first approach across larger functions.
When to Use Switch, a Ternary, or Early Returns
else if is one of several selection tools, but the alternatives solve different shapes of problem.
Use switch when one expression is repeatedly compared with exact values:
function describeStatus(status) {
switch (status) {
case "draft":
return "still being edited";
case "review":
return "waiting for review";
case "published":
return "visible to readers";
default:
return "unknown status";
}
}
console.log(describeStatus("review"));
waiting for review
A switch starts at the first case whose expression is strictly equal to its input. Without a break, return, or another control transfer, execution continues into later clauses. Returning from every branch avoids that fallthrough here. JavaScript Switch Statement: A Visual Guide covers that behavior with larger examples.
Use the conditional operator, often called a ternary, for one concise value choice:
const score = 64;
const result = score >= 60 ? "pass" : "retry";
console.log(result);
pass
The condition selects one of two expressions. A nested ternary can represent more branches, but an else if chain gives each condition and result their own visible block.
Use early returns for guard clauses that reject invalid or exceptional inputs before the main work:
function classifyScore(score) {
if (!Number.isFinite(score)) {
return "invalid score";
}
if (score < 0 || score > 100) {
return "score out of range";
}
if (score >= 90) {
return "distinction";
}
if (score >= 75) {
return "merit";
}
if (score >= 60) {
return "pass";
}
return "retry";
}
console.log(classifyScore(NaN));
console.log(classifyScore(105));
console.log(classifyScore(82));
invalid score
score out of range
merit
These standalone if statements still select one result because every matching branch returns from the function. The early checks remove invalid inputs, then the ordered thresholds classify the valid score.
Keep else if when you have ordered predicates or overlapping ranges and need one winning branch. Use switch for repeated exact-value cases, a ternary for one small value choice, and early returns when guard clauses make the main path easier to follow.
These choices appear throughout JavaScript Fundamentals, where conditionals sit beside the comparison, function, and control-flow rules they depend on.
Frequently asked questions
How do you write else if in JavaScript?
else if as two words, followed by a condition in parentheses and a block in braces. JavaScript has no elseif or elif keyword.How does an else if chain work in JavaScript?
Can more than one else if branch run?
else if chain selects at most one branch because testing stops after the first match. Use separate if statements when several actions may need to run.Does an if condition have to equal true?
true.When should I replace else if with switch?
switch when one expression is repeatedly compared with exact case values. Keep else if for ordered predicates, ranges, or conditions that test different expressions.