What you'll be able to do
By the end of this page you should be able to scan your code against a short beginner-bug checklist and recognize several failure patterns before they waste an afternoon.
Previous post: debugging with console and breakpoints.
Who this is for
- People mid-project who keep hitting "weird" behavior
- Students reviewing homework before submit
- Anyone who wants a printable mental list, not theory
You can skip this if these already feel obvious — skim for gaps, then move on.
Checklist (use it like a runway walk)
1. Types: string vs number
"10" + 20; // "1020"
Number("10") + 20; // 30
Scenario A — form values are strings until you convert.
Scenario B — API JSON numbers are fine; query params are strings.
2. Off-by-one in loops and slices
for (let i = 0; i <= arr.length; i++) {
/* last i is out of range */
}
Scenario A — <= length vs < length.
Scenario B — slice end index is exclusive — easy to drop the last item.
3. DOM null
document.getElementById("missing").textContent = "x"; // throws
Scenario A — script in <head> before the element exists.
Scenario B — typo in id.
4. Async timing
let data;
fetch("/api").then((r) => r.json()).then((d) => (data = d));
console.log(data); // undefined still
Scenario A — using data before the promise settles.
Scenario B — UI updates inside then/await, not on the next line after starting fetch.
5. Mutation surprises
const a = [1, 2];
const b = a;
b.push(3); // a also changes
Scenario A — "copied" array that was only a reference.
Scenario B — sorting in place and losing the original order.
6. == vs ===
Scenario A — 0 == "" is true with ==.
Scenario B — prefer === unless you have a rare intentional coercion.
A tiny practice file
<!DOCTYPE html>
<html>
<body>
<ul id="list"></ul>
<script>
const items = ["a", "b", "c"];
const list = document.getElementById("list");
// Fix the off-by-one if you spot it
for (let i = 0; i < items.length; i++) {
const li = document.createElement("li");
li.textContent = items[i];
list.appendChild(li);
}
</script>
</body>
</html>
Break it on purpose with i <= items.length and watch the console.
Mistakes I see a lot
1. Blaming the framework when the bug is a string total or a null node.
2. Fixing one checklist item and not re-testing neighbors (async + DOM together).
3. Silent catch that swallows the real error.
What to try before the next post
- Run this checklist on one of your old scripts.
- Keep a personal "bugs I hit" note with one line each.
- Re-read the debugging post if you still guess instead of observe.
Next in this series: clean code habits for juniors — naming, small functions, and readable structure without dogma.
Try this next outside the series
Engineering habits only stick when they show up in testing, security, and maintenance work.
- React Testing Library basics — turn clean habits into repeatable checks instead of guesses
- Node.js security basics — connect beginner discipline to safer real-world code