JavaScript, properly.

Most JavaScript courses teach you to recognize syntax. This one teaches you to predict what code will do before you run it — because that's the skill that separates someone who's "done a JS course" from someone who can debug a real bug. Nine stages, real code, projects you'd actually put on a portfolio.

Duration
9–10 weeks
Format
Project-based
Prerequisite
None
You'll build
6 real projects

Every stage follows the same shape

Why it matters, specifically what to learn, a real code example, something to build, and one question to check you actually understood it — not just watched it.

Nine stages, in this order

Each stage leans on the one before it — closures don't make sense until you understand scope, and async doesn't make sense until you understand the call stack.

STAGE 00

How JavaScript actually runs

Week 1

Most courses jump straight into syntax and skip this — which is exactly why so many self-taught developers can write code that works but can't explain why a bug is happening.

What you'll learn
  • The call stack and execution context — what happens when a function runs
  • Hoisting: why var, function declarations, and function expressions behave differently
  • The two-pass way the engine reads your file before running it
Code
console.log(a); // undefined, not an error — why?
var a = 5;

sayHi(); // works — function declarations are fully hoisted
function sayHi() { console.log("hi"); }

sayBye(); // TypeError — sayBye is not a function
var sayBye = function() { console.log("bye"); };
BuildNo app this week — take 5 hoisting/scope snippets and write down what each one logs before running it. Score yourself. This is the single highest-leverage exercise in the whole path.
Self-checkWhat does the first line log — undefined, 5, or a ReferenceError? Explain hoisting in one sentence before you scroll up to check.
STAGE 01

Values, types & coercion

Week 1–2

“Just use ===” is advice you can follow without understanding. This stage makes sure you know the actual coercion rules underneath it.

What you'll learn
  • Primitives vs. reference types — what “copied by value” means for objects and arrays
  • Type coercion rules for +, -, and equality — not just that they exist, but why
  • Template literals, and the real difference between == and ===
Code
console.log(1 + "1");   // "11" — number coerced to string
console.log("5" - 1);   // 4   — string coerced to number
console.log([] + []);   // ""  — both arrays stringify to empty
console.log(0 == "0");  // true  — coercion kicks in
console.log(0 === "0"); // false — no coercion, different types
BuildA small validator library — validatePAN(), validateIndianPhone(), validatePinCode(). Real regex, real edge cases, something you'll reuse later.
Self-checkWhy does 0 == [] evaluate to true? Trace the coercion steps by hand before looking it up.
STAGE 02

Functions & closures

Week 2–3

Closures are usually taught as “a function remembers its outer variables,” which is true and useless until you build something that only works because of it.

What you'll learn
  • Function declarations vs. expressions vs. arrow functions — and where this differs
  • Lexical scope and closures: what's actually being “remembered,” and why
  • Higher-order functions: functions that take or return other functions
Code
function debounce(fn, delay) {
  let timer;
  return function (...args) {
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), delay);
  };
}
// The returned function "closes over" timer —
// every call shares that same variable, across calls.
BuildWrite your own debounce() and throttle() from scratch — not imported from lodash. This is the exercise that actually tests whether closures clicked.
Self-checkIf you call debounce(fn, 300) three times in quick succession, how many times does fn actually run — and when?
STAGE 03

Arrays, objects & shaping data

Week 3

Almost every real frontend task is “I have data shaped like X, I need it shaped like Y.” This stage makes that fast instead of painful.

What you'll learn
  • map / filter / reduce / find — and when reduce is the wrong tool
  • Destructuring, spread/rest, and shallow vs. deep copy pitfalls
  • Grouping, sorting, and flattening nested data
Code
const orders = [
  { city: "Pune", amount: 450 },
  { city: "Delhi", amount: 900 },
  { city: "Pune", amount: 220 },
];

const byCity = orders.reduce((acc, order) => {
  acc[order.city] = (acc[order.city] || 0) + order.amount;
  return acc;
}, {});
// { Pune: 670, Delhi: 900 }
BuildTake a real messy dataset (weather or transit data works well) and write five data-transform functions: group by, sort by, top-N, average, flatten.
Self-checkWhen should you reach for reduce() instead of a plain for loop — and when does reduce actually make the code harder to read?
STAGE 04

The DOM & events, done right

Week 4

Everyone eventually reaches for a framework — but if you've never manipulated the real DOM by hand, you won't understand what the framework is doing for you.

What you'll learn
  • DOM traversal and manipulation without a framework
  • Event delegation, and why it matters once a list can grow
  • Accessible forms — labels, focus states, keyboard navigation
Code
// Bad: one listener per card — breaks for cards added later
document.querySelectorAll(".card").forEach(card =>
  card.addEventListener("click", handleClick)
);

// Good: one listener on the parent, works for future cards too
document.querySelector(".board").addEventListener("click", (e) => {
  const card = e.target.closest(".card");
  if (card) handleClick(card);
});
BuildA vanilla-JS Kanban board — three columns, drag cards between them with native drag events, persist state to localStorage. No framework.
Self-checkWhy exactly does the “bad” example break when a new card is added to the board after the listeners were attached?
STAGE 05

Async JavaScript

Week 5

Async/await hides the event loop from you — which is great, until a bug forces you to understand it anyway. This stage builds it the historical way so the “why” sticks.

What you'll learn
  • Callbacks → Promises → async/await, and why each one exists
  • The event loop: microtasks vs. macrotasks (where most developers stay fuzzy)
  • fetch, and error handling with try/catch
Code
console.log("1");
setTimeout(() => console.log("2"), 0);
Promise.resolve().then(() => console.log("3"));
console.log("4");

// Output: 1, 4, 3, 2
// Sync code first, then microtasks (Promises),
// then macrotasks (setTimeout) — even at 0ms.
BuildA live weather dashboard hitting a real public API (no key required — Open-Meteo works well) with proper loading and error states, not just the happy path.
Self-checkRewrite the code above using async/await instead of .then(). Does the logged order change? Why or why not?
STAGE 06

Modules & modern tooling

Week 6

This is the stage that makes every tutorial you've seen with a vite.config.js or a package.json actually make sense, instead of being magic you copy.

What you'll learn
  • ES modules — import / export, default vs. named
  • npm, package.json, and what a bundler like Vite is actually doing
  • Environment variables, and the real difference between browser and Node
Code
// math.js
export function add(a, b) { return a + b; }
export const PI = 3.14159;

// main.js
import { add, PI } from "./math.js";
console.log(add(2, PI));
BuildRefactor the Stage 5 weather dashboard into a proper Vite project — split it into modules, add a .env for config, deploy it.
Self-checkWhat's the actual difference between a default export and a named export — and when would you reach for each?
STAGE 07

Prototypes, classes & this

Week 7

class syntax hides the prototype chain underneath it. Understanding what it compiles to is what lets you debug this-binding bugs instead of guessing.

What you'll learn
  • The prototype chain — what class actually is under the hood
  • The four rules of this binding: implicit, explicit, new, arrow
  • call, apply, and bind
Code
const user = {
  name: "Asha",
  greet() { console.log(`Hi, I'm ${this.name}`); },
};

const greetFn = user.greet;
greetFn();          // "Hi, I'm undefined" — lost its binding
user.greet();        // "Hi, I'm Asha" — called as a method
greetFn.call(user);  // "Hi, I'm Asha" — this restored explicitly
BuildA tiny state-management library from scratch — subscribe() / publish(), ~40 lines. This teaches you what Redux or Zustand are doing underneath.
Self-checkWhy does greetFn() lose its this binding, but user.greet() doesn't?
STAGE 08

Testing & debugging like a professional

Week 8

This is the stage that's usually skipped entirely in beginner paths — and it's the single biggest tell of who's actually shipped production code.

What you'll learn
  • DevTools: breakpoints, conditional breakpoints, the network and performance tabs
  • Writing unit tests with Vitest
  • The TDD mindset — write the failing test first
Code
import { it, expect } from "vitest";
import { debounce } from "./debounce.js";

it("only calls fn once after rapid calls", async () => {
  let count = 0;
  const fn = debounce(() => count++, 100);
  fn(); fn(); fn();
  await new Promise(r => setTimeout(r, 150));
  expect(count).toBe(1);
});
BuildWrite real tests for the debounce, throttle, and state-library code you built in earlier stages.
Self-checkWhat's one real bug your debounce function might have that this test would catch — but clicking around manually never would?

The capstone: build one real thing

Pick one — an expense tracker with hand-drawn Canvas charts (no chart library, so you actually understand what one is doing), or a Markdown note-taking app with live preview. This is the artifact that goes on your resume, not a certificate.

Persists state to localStorage
Makes at least one real fetch call
Has tests for its core logic
Forms are keyboard-accessible
Deployed live — not just on your laptop
Deliberately no framework — this track is JS fundamentals

Common pitfalls

  • Tutorial hell. Watching a course isn't the same skill as building. Cap video time at 20% of your hours.
  • Skipping the "why." Memorizing that closures are "functions with memory" without ever needing one is why it doesn't stick.
  • Searching too fast. Stuck past 25 minutes? Write down exactly what you tried before you search.
  • Framework-first. Reaching for React before this path is finished means you'll never know which parts of your app are React and which are just JavaScript.

Resources worth your time

  • MDN Web Docsreference
  • javascript.infodeep dives
  • Eloquent JavaScriptfree book
  • freeCodeCamppractice
  • Vitest docstesting