Skip to content

Best Practices and Common Mistakes ​

Code that works today and code you can still understand next year are two different achievements. This lesson is about the second one.

Look at how far you've come. You can store and shape data, make decisions, build and change the page, react to people, load data from servers, and remember things between visits. That's the whole foundation of front-end JavaScript.

As in the HTML and CSS tracks, the last stretch before the final project is about doing it well. JavaScript is even more forgiving than HTML: code full of quiet problems can still appear to work, right up until the day it doesn't. These habits are what keep that day from coming.

Habits for readable code ​

const by default, let when it changes, never var. When someone reads const, they know that value stays put. That's one less thing to track in their head. (Variables, Scope and Closures.)

Names that explain themselves. const loavesLeft = 3 beats const x = 3. Functions get verbs (calculateTotal, showMenu); booleans read like yes-or-no questions (isOpen, hasDiscount). If you need a comment to explain what a variable holds, rename the variable instead.

Small functions that do one job. If a function is longer than your screen, or its name needs an "and" in it, split it. Small functions are easier to read, test, and reuse. (Functions.)

Early returns instead of deep nesting.

js
// Hard to follow: the real work is buried three levels deep
function addToCart(product) {
	if (product) {
		if (product.stock > 0) {
			if (!cart.includes(product)) {
				cart.push(product);
			}
		}
	}
}

// Flat: handle the "no" cases first, then do the work
function addToCart(product) {
	if (!product) return;
	if (product.stock === 0) return;
	if (cart.includes(product)) return;
	cart.push(product);
}

Comment the why, not the what. // add 1 to count above count += 1 tells nobody anything. // The API counts pages from 1, not 0 saves someone an afternoon.

Keep the three languages apart. JavaScript switches classes and attributes; CSS decides what they look like; HTML holds the content and structure. Avoid element.style for anything a class could do. (Where CSS Meets JavaScript.)

Habits for safe code ​

===, always. The loose == "helps" in ways that hide bugs. (Operators and Comparisons.)

Convert on purpose. Form fields, dataset, and storage all give you strings. Call Number() before doing math. (Numbers, Strings, and Booleans.)

Format for people with Intl. Intl.NumberFormat turns 1234.5 into $1,234.50 (or 1.234,50 €, depending on the country), and Intl.DateTimeFormat does the same for dates. It's more reliable than gluing symbols onto toFixed results. (Functions.)

textContent for anything from outside. Visitor input and server data never go into innerHTML. (Changing Text, Attributes, and Classes.)

Handle errors at the edges, and never swallow them. Wrap parsing, network calls, and storage in try/catch, and always do something useful in the catch. (Errors and Debugging.)

The browser is the receptionist, not the security guard. Anything in front-end code can be read and changed by visitors. Real checks and real secrets live on the server. (Forms and Custom Validation, Loading Data with fetch.)

Habits for pages people can use ​

Real buttons for actions, real links for navigation. A <button> works with the keyboard for free; a clickable <div> doesn't. A link goes somewhere; a button does something. (Events.)

Keep accessible state in sync. When JavaScript opens something, update aria-expanded. When it shows a message, use aria-live or role="status" so screen readers announce it. When a dialog or error appears, move focus to where the person needs to be.

Respect motion preferences in JavaScript too. CSS media queries don't cover animations started from JavaScript. Check window.matchMedia('(prefers-reduced-motion: reduce)').matches before starting one.

Progressive enhancement. Build the page so its content and basic links work even if the JavaScript fails to load on a flaky connection, then layer the interactivity on top, the same idea from Where HTML Meets CSS and JS.

Don't block the cook. Long loops freeze the whole page. Slow work, like loading data, should be awaited, never waited on in a loop. (Timers and the Event Loop.)

The mistakes everyone makes ​

Here's a gallery of the bugs almost every beginner writes at least once, with the fix. If you recognize a few, welcome to the club.

MistakeWhat you seeThe fix
if (total = 0)The condition is always false, and total gets set to 0=== for comparing, = only for assigning
'2' + 3 from a form field'23' instead of 5Number(field.value)
(x) => { x * 2 }undefinedAdd return, or drop the braces
A missing awaitPromise {...} instead of dataawait the promise inside an async function
A selector typo, or a script running too earlyCannot read properties of nullCheck the selector; use defer
quantity || 1 when 0 is a valid answer0 becomes 1quantity ?? 1
Adding a listener inside another listenerThe action runs twice, then three times...Add each listener once, outside
const copy = original for an arrayChanging the copy changes the original[...original] or structuredClone
innerHTML with visitor inputA security hole (XSS)textContent, or createElement
setInterval with no clearIntervalTimers that pile up and never stopKeep the id and clear it
Passing object.method as a callbackthis is lost() => object.method()
fetch without checking response.okA 404 page treated as real dataif (!response.ok) throw ...

Tools that catch mistakes for you ​

You don't have to spot every problem by eye. Professional teams let tools do the boring checking:

  • A formatter, most often Prettier, rewrites your code with consistent spacing and line breaks every time you save. No more debates about style.
  • A linter, most often ESLint, reads your code and warns you about likely bugs: == instead of ===, variables you never use, a let that should be const, a missing await. Many of the mistakes in the table above can be caught this way before you even run the code.
  • Your editor, set up with both, underlines problems as you type. Extensions & Customization covers adding them.

Try it: bug hunt ​

This little order form "works." Nothing turns red in the console. But it's full of the mistakes from this lesson. How many can you find and fix?

HTML

JavaScript

Preview

Console

Nothing logged yet. Anything you pass to console.log() shows up here.

Try it yourself ​

Fix every problem you can find. Here's the checklist, so you know when you're done (try first, then peek):

  1. Every var should be const or let. Which ones need to be let?
  2. x is a meaningless name. Rename it to say what it holds.
  3. Both comparisons use == or !=. Make them strict, and compare against real numbers instead of strings.
  4. price and qty are strings. Convert them with Number().
  5. A 0% discount becomes 10%, because || treats 0 as falsy. Use ??, or check the value properly.
  6. Both innerHTML lines display text the visitor typed. Switch to textContent. (Try typing <b>bold</b> as the item name before and after.)
  7. The nested if inside else can be flattened with an early return.
  8. Money should always show two decimal places, like $14.40, not $14.4. Format the total with toFixed(2), or better, with Intl.NumberFormat.

If you found all eight, you're reviewing code like a professional. If you found four, that's four more than you'd have spotted when this track began.

Check your understanding ​

A friend's click handler runs twice on the second click, three times on the third, and so on. What is the most likely cause?
Which tool warns you about likely bugs, like using == or leaving a variable unused?
What is the main benefit of early returns?

Up next ​

There's one thing left to do: take the profile page you built in HTML and styled in CSS, and bring it to life. Head to Final Project: Bring Your Profile Page to Life.