How does if decide what runs?
An if statement runs a block of code only when its condition is true. The condition goes in round brackets, and the code to run goes in curly braces. If the condition is false, JavaScript skips the block and carries on after it.
Add else for what should happen otherwise. Add else if for more cases in between. JavaScript checks each condition from top to bottom and runs the first branch whose condition is true. After that it skips the rest of the chain, even if later conditions are also true.
That order matters. If the bakery checks loavesLeft > 0 before loavesLeft > 20, a shelf of 30 loaves matches the first test and never reaches the second. Put the narrow or special cases first and the broad ones last.
Always use braces, even for one line. JavaScript allows if (x) doThing(); without them, but adding a second line later then runs it every time, which is a classic bug.
const loaves = 30;
if (loaves > 20) {
console.log("Plenty");
} else if (loaves > 0) {
console.log("Some left");
} else {
console.log("Sold out");
}

loaves > 20 wins, so the broader loaves > 0 never gets a turn.What can go inside the condition?
Any expression can go in the brackets. Most often it is a comparison: === for equal, !== for not equal, and <, >, <=, >= for sizes. Use the triple-equals forms. == converts types before comparing, so 0 == "" is true, which surprises everyone.
A single = inside a condition is an assignment, and it is one of the most common bugs in beginner and AI-written code. if (member = true) sets member to true and then always runs the branch. If member was declared with const, it throws an error instead, which is the friendlier outcome.
You can also call a method that returns true or false, such as name.includes("rye") or Array.isArray(list). A function that answers a yes or no question usually has a name starting with is or has, which makes the if read like a sentence.
const order = "rye and spelt";
if (order.includes("rye")) {
console.log("Rye is on the order");
}What counts as true and false?
A condition does not have to be a real boolean. JavaScript converts whatever you give it. Values that act like false are called falsy, and there are only a handful: false, 0, -0, 0n, the empty string "", null, undefined and NaN.
Every other value is truthy. That includes some that look empty: the string "0", the string "false", an empty array [] and an empty object {} are all truthy.
This makes short checks possible. if (name) is true when name holds any non-empty text, which is a quick way to ask whether someone typed something. It also creates traps. if (stock) treats a real stock count of 0 the same as a missing value. When 0 is a valid answer, compare directly: if (stock === undefined) or if (stock > 0).
To test an empty array, check its length: if (basket.length === 0). Writing if (basket) is always true for an array, even an empty one.
const values = [0, "", "0", [], null, "rye", NaN];
for (const value of values) {
console.log(JSON.stringify(value), value ? "truthy" : "falsy");
}How do && and || combine conditions?
&& means and: both sides must be true. || means or: at least one side must be true. A leading !isOpen flips the value, so it is true when the shop is closed.
Both operators stop early. With &&, if the left side is falsy, the right side is never run. That is why user && user.name was a common way to avoid reading a property of null. Today optional chaining, user?.name, does that more clearly.
When you mix them, && binds tighter than ||, like multiplication before addition. a || b && c means a || (b && c). Add brackets whenever both appear, so nobody has to remember the rule.
Long conditions are hard to read. Give the parts names first: const isWeekend = day === 6 || day === 0; then if (isWeekend && isSunny). The Step lens shows each named value, which makes it easy to see which part was false.
const day = 6;
const isSunny = true;
const isWeekend = day === 6 || day === 0;
if (isWeekend && isSunny) {
console.log("Bird walk at 8am");
}When is the ternary operator a good fit?
The ternary picks between two values in one expression: condition ? valueIfTrue : valueIfFalse. It is ideal when you are choosing a value to store or display, such as a label, a class name or a plural ending.
` ${count} ${count === 1 ? "loaf" : "loaves"} is a typical use. Writing that as an if` would take five lines for one word.
Avoid nesting ternaries or using them to run actions. a ? b ? x : y : z is legal and hard to read, and AI tools produce it more than people do. When there are three or more outcomes, or when each branch does several things, use an if chain.
const count = 1;
const text = `${count} ${count === 1 ? "loaf" : "loaves"} left`;
console.log(text);When should you use switch, and when an object lookup?
A switch compares one value against a list of cases using ===. Each case ends with break; without it, JavaScript falls through and runs the next case too. Forgetting break is the usual switch bug.
A switch reads well when each case runs different statements. When each case only maps a value to another value, an object is shorter and harder to get wrong. The keys are the cases, the values are the answers, and ?? supplies a default when the key is missing.
The lookup also keeps data apart from logic. Adding a new size of loaf means adding one line to the object, with no new branch to test.
const size = "large";
const prices = { small: 3, medium: 4.5, large: 6 };
const price = prices[size] ?? 0;
switch (size) {
case "small":
console.log("Fits in a bag");
break;
case "large":
console.log("Needs a box");
break;
default:
console.log("Standard bag");
}
console.log(price);What is an early return?
Inside a function, return stops the function straight away. You can use that to deal with the odd cases first and leave the main path unindented. This pattern is called an early return or a guard clause.
Without it, code drifts to the right: an if inside an if inside an if, with the real work buried in the middle and a pile of else blocks at the end. With guards, each bad case is handled in two or three lines at the top, and the rest of the function can assume the input is fine.
You will meet functions properly in the next-but-one lesson. For now, read the example as: if there is no name, stop; if the name is too short, stop; otherwise greet.
function greet(name) {
if (!name) {
return "Please enter a name.";
}
if (name.length < 2) {
return "That name looks too short.";
}
return `Welcome to the bird club, ${name}.`;
}
console.log(greet(""));
console.log(greet("Ada"));How do you check which branch ran?
When a condition does not do what you expect, find out what it actually saw. Log the values just before the if: console.log(loavesLeft, typeof loavesLeft). A number stored as text, such as "0" from a form field, is truthy and never equals the number 0.
The Step lens runs the code line by line. Watch the arrow jump past branches whose condition was false, and look at the variable panel to see the values the condition compared.
When reviewing AI-written conditions, look for == instead of ===, a single = inside the brackets, if (array) used to mean not empty, and long chains of else if that compare one value against fixed strings. That last one is usually shorter as an object lookup.
Field notes
- An
ifruns its block only when its condition is true. else ifadds another check, and only the first true branch runs.- Compare with
===so the value and its type both have to match. - Values like 0, empty text and
nullcount as false in a condition.
Easy to get wrong
A single = assigns the value and the branch always runs. Use === to compare, or write if (isMember) for a boolean.
Every array is truthy, even an empty one. Test length to know whether it has items.
0 is falsy, so a real count of zero is treated as missing. Compare against undefined or null when 0 is a valid value.
The first true condition wins. Put the narrower test first, or the later branch can never run.
Questions people ask
Should I write if (x === true) or if (x)?
When x is a real boolean, if (x) reads better. When x might be other things, such as a number or text, be explicit about what you are testing so truthiness does not surprise you.
Is == ever the right choice?
The one common use is value == null, which is true for both null and undefined. Everywhere else use ===. Linters flag == for that reason.
Can a ternary run code instead of picking a value?
It can, as in ok ? save() : warn(), and it works. Most teams prefer an if for actions and keep the ternary for choosing values, because readers expect that.
Is switch slower or faster than if?
The difference is too small to matter on a web page. Choose whichever is easiest to read for the case in front of you.
What does ?? do compared with ||?
a || b uses b whenever a is falsy, so 0 and empty text are replaced. a ?? b uses b only when a is null or undefined, so 0 and empty text are kept.