The idea
Programs become useful when they decide (is this order eligible for free shipping?) and repeat (add up every item in the cart). JavaScript's tools for both look like most C-style languages: curly braces and round brackets instead of Python's indentation. The logic is the same; the traps are different, especially around which values count as "true".
if, else if, else
Toko Kita's shipping rule has three tiers: free for orders of 300000 or more, 10000 from 150000, and 20000 for anything smaller. That's a chain of decisions, and it looks almost the same as Python's if/elif/else, just with brackets and curly braces:
function shippingFee(total) {
if (total >= 300000) {
return 0;
} else if (total >= 150000) {
return 10000;
} else {
return 20000;
}
}
console.log(shippingFee(450000), shippingFee(200000), shippingFee(50000));
0 10000 20000
Conditions go in round brackets, blocks in curly braces. Order matters: the first true condition wins, so check the most specific case first.
The ternary operator
For choosing between two values, there's a one-line form: condition ? valueIfTrue : valueIfFalse.
const stock = 0;
const label = stock > 0 ? "In stock" : "Sold out";
console.log(label);
Sold out
Use it for simple value choices. For anything with more than two branches or side effects, if reads better.
Truthy and falsy
if accepts any value, not only booleans. These six values count as false (they're "falsy"): false, 0, "" (empty string), null, undefined and NaN. Everything else is truthy, including "0", [] and {}.
const checks = [0, "", "0", [], null, "Ayu"];
for (const value of checks) {
console.log(JSON.stringify(value), value ? "truthy" : "falsy");
}
0 falsy
"" falsy
"0" truthy
[] truthy
null falsy
"Ayu" truthy
The trap: an empty array is truthy, unlike Python. Check cart.length > 0, not if (cart).
Guarding against missing data: ?? and ?.
Data from forms and servers is often incomplete. A customer hasn't set a nickname, or hasn't entered an address yet. In JavaScript, reading something that doesn't exist gives you undefined or null, and trying to go one step further, like reading the city of a missing address, crashes the page. Two small operators handle this safely:
const user = { name: "Ayu", address: null, settings: { currency: "IDR" } };
console.log(user.nickname ?? user.name); // ?? : use the right side if the left is null/undefined
console.log(user.address?.city); // ?. : stop safely if address is null
console.log(user.settings?.currency ?? "IDR");
const discount = 0;
console.log(discount || 10, discount ?? 10); // || treats 0 as missing; ?? doesn't
Ayu
undefined
IDR
10 0
a ?? bgivesbonly whenaisnullorundefined.a?.bgivesundefinedinstead of crashing whenaisnullorundefined. Without it,user.address.citywould throw "Cannot read properties of null".a || bgivesbfor any falsya, including0and"", which is often a bug: a real discount of 0 gets replaced by 10.
switch
switch compares one value against several options with ===:
function roastNote(roast) {
switch (roast) {
case "light":
return "Bright and fruity";
case "medium":
return "Balanced and sweet";
case "dark":
return "Bold and smoky";
default:
return "Unknown roast";
}
}
console.log(roastNote("medium"), "|", roastNote("extra"));
Balanced and sweet | Unknown roast
Inside a function, return ends each case. Outside one, each case needs a break, or execution "falls through" into the next case. A lookup object (const notes = { light: "...", dark: "..." }; notes[roast] ?? "Unknown") is often cleaner.
Loops
Most of the work in a shop page is going through lists: every item in the cart, every product in a category. JavaScript has a few kinds of loop, and this example uses the three you'll meet most often, on a small cart:
const cart = [
{ name: "Arabica Gayo", price: 95000 },
{ name: "Paper filters", price: 35000 },
{ name: "French Press", price: 245000 },
];
for (let i = 0; i < cart.length; i++) { // classic counter loop
console.log(i + 1, cart[i].name);
}
for (const item of cart) { // for...of: each value
if (item.price < 50000) continue; // skip this one
console.log("Premium:", item.name);
}
let stock = 10;
let days = 0;
while (stock > 0) { // repeat while a condition holds
stock -= 3;
days++;
}
console.log("Sold out after", days, "days");
1 Arabica Gayo
2 Paper filters
3 French Press
Premium: Arabica Gayo
Premium: French Press
Sold out after 4 days
for (let i = 0; i < n; i++)when you need the index.for (const item of array)for each value: the everyday choice.while (condition)when you don't know in advance how many rounds you need. Make sure the condition eventually becomes false.breakleaves the loop;continueskips to the next round.
Avoid for...in on arrays: it loops over keys (as strings), not values. It's meant for objects, and even there Object.entries(obj) with for...of is clearer.
if/else if/else for branches, the ternary for choosing values, switch or a lookup object for many fixed options. Remember the six falsy values, and that [] is truthy. Use ?? and ?. for missing data. Loop with for...of by default.
Why this matters for clean code
Return early to keep code flat: if (!user) return; at the top beats wrapping the whole function in an if. Prefer ?? over || for defaults so valid zeros survive. And when a chain of ifs maps fixed values to results, a lookup object turns ten lines of branching into data.
Recap
if (cond) { } else if (cond) { } else { }; first true branch wins.cond ? a : bfor value choices.- Falsy:
false,0,"",null,undefined,NaN.[]and{}are truthy. ??defaults only fornull/undefined;?.reads safely through missing objects.switchwithreturn/break, or a lookup object.for,for...of,while;breakandcontinue. Notfor...inon arrays.