The most honest JavaScript introduction, freely available online. Updated for ES2024.
Why this book
Eloquent JavaScript has been online for free since 2011. Haverbeke updates it with every major ECMAScript revision, no exception: the fourth edition covers ES2024. Most JavaScript books age in a drawer; this one has been a living document for fifteen years.
But what makes it different isn't the price or the update cadence. It's the tone. Haverbeke opens the introduction by admitting he quickly came to despise JavaScript the first time he used it. Then he explains, a few pages later, that he eventually came to like it. That arc is the whole book: start from honest confusion, follow it through to real understanding. There's no hand-waving, no shortcuts. He shows you the binary, then the assembly, then the JS — and you understand why languages exist.
The ideas that stay
1A program is a building of thought
The introduction shows the same program — add numbers 1 to 10 — written in raw binary, then readable assembly, then JavaScript's while loop, then sum(range(1, 10)). The moral is explicit: "A good programming language helps the programmer by allowing them to talk about the actions the computer has to perform at a higher level" (p. 8). This framing, early and concrete, answers the "why do languages exist" question better than most CS textbooks.
2Functions are values — the real rupture
In many languages, functions are special entities. In JavaScript, a function is a value like any other: you can store it in a variable, pass it as an argument, return it from another function. Haverbeke demonstrates this by storing a function in a binding called launchMissiles, then reassigning it to a no-op based on a condition. The fact that this is legal — and useful — is the conceptual key that unlocks the rest of the book.
3Closures: the environment travels with the function
When a function is created, it captures its surrounding scope. multiplier(2) returns a function that multiplies its argument by 2 — and that returned function keeps access to the factor binding even after multiplier has returned. "A good mental model is to think of function values as containing both the code in their body and the environment in which they are created" (p. 72). This one concept explains event handlers, factories, partial application, and a large portion of npm packages.
4filter, map, reduce — thinking in transformations
Chapter 5 works through a dataset of human writing scripts (Latin, Arabic, Han...) using higher-order functions. The recipe analogy lands well: detailed step-by-step instructions vs. "soak, simmer, chop, add" — the second requires understanding a few extra words, but says far more in less space. The final example, computing the average year of origin for living vs. extinct scripts, fits in a single readable expression: SCRIPTS.filter(s => s.living).map(s => s.year). That's what thinking in transformations looks like.
5Prototypes and the secret life of this
JavaScript objects are linked to other objects through a prototype chain. When you access a property that an object doesn't have, the runtime walks up the chain until it finds it or reaches null. Object.getPrototypeOf([]) == Array.prototype — true. This explains why arrays have .map() and .filter() without you ever defining them. The chapter also clarifies why this behaves differently in arrow functions vs regular functions, which is the source of more confusion than any other single JS feature.
6JavaScript is deliberately liberal — this has costs
The language accepts almost anything you type and interprets it in ways you didn't intend. Skip let on a binding inside a loop: outside strict mode, you've just created a global variable and JS didn't say a word. NaN produced by an invalid operation propagates silently through your program until you get wrong output with no error message. Haverbeke names these clearly: "Finding the source of such problems can be difficult" (p. 192). The fix — strict mode, TypeScript — is presented honestly, not evangelized.
7From callback hell to async/await
JavaScript runs on a single thread but needs to handle operations that take time. The chapter walks the full path: callbacks (you pass a function to be called when done), then Promises (a receipt for a future value), then async/await (pseudosynchronous code that hides the Promise machinery). "An async function implicitly returns a promise and can, in its body, await other promises in a way that looks synchronous" (p. 283). You still need to understand Promises underneath, but async/await is where you live day to day.
8Modules: LEGO instead of mud
Before ES modules (2015), all JavaScript ran in a shared global scope, and any two scripts could overwrite each other's variables without warning. Haverbeke calls the modular alternative "LEGO, where pieces interact through well-defined connectors, and less like mud, where everything mixes with everything else" (p. 250). Import, export, and NPM (with over three million packages, "a large portion of those are rubbish, to be fair" — p. 254) are the tools. The honest caveat about npm quality is characteristic of the book's tone.
Three things I didn't know before reading it
- Haverbeke uses a crow named Carla to teach async programming. She's hacking a WiFi by timing attack — testing each digit of the passcode and measuring how quickly the access point rejects it. The whole chapter (callbacks → Promises → async/await) flows through this single absurd narrative. It's the best pedagogical device in any programming book I've read.
- The introduction shows the same program (sum 1 to 10) in binary, pseudo-assembly, imperative JS, and finally
sum(range(1, 10)). What looks like a warmup is actually the deepest argument in the book: a language that lets you name concepts gives you power that raw instructions can't. It takes three pages and it sticks forever. - The book's license is Creative Commons. Haverbeke releases every edition for free online because he genuinely thinks that's the right thing to do. He also sells a paper version — with a bonus chapter — for those who want to support the work. That model has kept the book alive and updated for fifteen years.
My take, honestly
The first twelve chapters build in the right order: functions as values first (the concept that unlocks everything), closures next (what you do with them), then filter/map/reduce (how to compose them), finally prototypes (why this behaves the way it does). Each concept rests on the previous one without skipping steps. The exercises don't ask you to reproduce an example — they pose an original problem that forces you to assemble what you just read, yourself.
The browser chapters (13 to 19) are more uneven. DOM manipulation and Canvas are well-explained, but they teach you a layer of abstraction that most developers will use through a framework (React, Vue) rather than directly. The platform game project in chapter 16 is fun but takes three chapters to build — it's a big investment if your goal is learning JS fundamentals rather than game development. These chapters haven't aged badly; they're just less essential than the first half.
In 2026, JavaScript is still the only language that runs natively in every browser. The AI generates a lot of it. Understanding closures and the prototype chain is exactly what you need to review AI-generated code and spot why something behaves oddly. Haverbeke's book, which has been free and continuously updated for fifteen years, is the clearest path to that understanding. There's no excuse not to read it.
Odilon
Still relevant in 2026?
The fourth edition was published in 2024 and covers ES2024 explicitly. Private class fields (#property), optional chaining (obj?.prop), structuredClone, top-level await — it's all there. The fundamentals chapter (closures, prototypes, event loop) are as relevant as ever because frameworks are built on top of them, not instead of them. The only part that ages is the DOM/browser section, which is still accurate but less representative of how frontend code is written today.
Who is it for?
Read it if
- You write JavaScript but feel like you're guessing why closures,
this, or Promises behave the way they do - You're starting out and want a single book that takes you from zero to Node.js, for free
- You review AI-generated JS and want a solid framework to judge it
- You like books that assume you're an adult: no hand-holding, real exercises
Skip it if
- You already understand closures, the prototype chain, and the event loop — you'll know by chapter 3
- You want a reference you can index and query, not a book you read: the MDN docs serve that role better
- You're looking for React, Vue, or TypeScript specifically — this book doesn't cover frameworks or typed JS
For going further
The closures and prototypes chapters pair directly with the JavaScript course on this site. For TypeScript (the typed layer above JS), Effective TypeScript by Dan Vanderkam is the natural next step. For modern async patterns in practice, the REST API course covers fetch and async/await in a real context.
Comments (0)