Every one of the snippets below looks fine. Clean, short, reasonable. The kind of code you'd nod at in a review and move on.
I've run each of these in Node to confirm — no tricks, no outdated browser quirks. Just JavaScript being JavaScript. Let's go through them one by one: the code, what you'd expect, what actually happens, and the fix.
This one looks like the most natural code in the world. You've got strings, you want numbers, parseInt converts strings to numbers. What could go wrong?
Here's the catch: map doesn't call your function with one argument. It calls it with three — the element, the index, and the whole array. And parseInt doesn't take one argument either. It takes two — the string, and the radix (the number base).
The lesson: never pass a multi-argument function directly into map, filter, or forEach. They always sneak extra arguments in.
JavaScript's default sort() doesn't compare numbers. It converts everything to strings first, then sorts alphabetically. And alphabetically, "10" comes before "80" comes before "9" — because "1" < "8" < "9". It's sorting words, not values.
The lesson: sort() without a compare function is almost never what you want for numbers. This one has bitten literally everyone at least once.
Quick sanity check. One tenth plus two tenths equals three tenths. First-grade math.
Computers store decimals in binary floating point, and some perfectly innocent-looking decimals — like 0.1 — can't be represented exactly in binary. It's like trying to write 1/3 in decimal: 0.3333... forever. The tiny leftover error accumulates, and your "equal" comparison fails.
This isn't even JavaScript-specific — Python, Java, and C all do the same thing. It's just how floats work.
The lesson: never trust === with decimal math. If money is involved, work in cents (integers), not dollars (floats).
Why? In the very first version of JavaScript, values were stored with a small "type tag" in front of them. Objects had tag 0. And null was represented as a null pointer — which is all zeros. So null accidentally wore the "object" nametag, and the check has returned 'object' ever since, for almost 30 years.
The lesson: typeof tells you the category, not the value. And null has been lying about its category since 1995.
This is the sneakiest one on the list, because the await keyword is right there. It looks like it must work.
What actually happens: "All saved!" prints first, while the saves are still running. I confirmed it — the log fires before any item finishes.
Why? forEach doesn't know or care about promises. It calls your async function, gets a promise back, and throws it on the floor. It never awaits anything. Your await inside the callback only pauses that one callback — the loop itself blasts through all items instantly and moves on.
(Need them to run in parallel instead? Use await Promise.all(items.map(...)) — that's the deliberate version of what forEach pretends to do.)
The lesson: forEach + async is a trap. The await inside looks like it controls the loop. It doesn't.
