BusinessEloquent JavaScript: A Modern Introduction to Programming
Not rated yetRate this bookEloquent JavaScript: A Modern Introduction to Programming teaches programming by developing working programs, not by memorising syntax in isolation. Marijn Haverbeke moves from values and functions to browser interfaces, asynchronous systems and server-side applications. This guide follows the fourth edition’s twenty-one chapters and six projects, with study tasks that test understanding through small, observable changes.
Free reading is available at the official source. Opens in a new tab.
FreeAbout this book
Eloquent JavaScript: A Modern Introduction to Programming teaches programming by developing working programs, not by memorising syntax in isolation. Marijn Haverbeke moves from values and functions to browser interfaces, asynchronous systems and server-side applications. This guide follows the fourth edition’s twenty-one chapters and six projects, with study tasks that test understanding through small, observable changes.
Chapter-wise summaries and study tasks
Values, Types, and Operators
The first chapter establishes the basic materials of JavaScript programs: numbers, strings, Boolean values, empty values and operators. Expressions combine values to produce new values, but the language’s conversion rules can make apparently similar expressions behave differently. Pay particular attention to operator precedence, comparisons, short-circuit evaluation and the difference between a value’s type and its printed appearance. Understanding these rules prevents later debugging from becoming guesswork. The goal is to predict an expression before running it and explain the result using the language’s model rather than a remembered example.
Study task. Predict ten expressions involving arithmetic, strings, strict equality and short-circuit operators. Run them and explain every disagreement with your prediction.
Program Structure
Program structure turns isolated expressions into sequences of decisions and repeated actions. Bindings name values, statements organise work, and control flow determines which statement executes next. Conditionals and loops are introduced alongside functions available in the environment, such as console.log. Trace how a loop changes its bindings and why its stopping condition eventually becomes false. Formatting and comments help expose structure, but a well-indented infinite loop remains incorrect. The exercises encourage building small complete programs, making this chapter a transition from recognising syntax to designing an algorithm.
Study task. Solve the loop exercises with a handwritten trace of the first five iterations. Include the binding values and the condition tested on each pass.
Functions
Functions create reusable computations and local scopes. The chapter compares function declarations, expressions and arrow notation, then develops closures, recursion and the call stack. A closure retains access to the environment in which a function was created; it is more than a function that happens to use an outer variable once. Distinguish return values from side effects, and identify which bindings belong to each invocation. Recursion becomes understandable when each call is treated as a separate activation with its own pending work. These ideas later support event handlers, modules and application state.
Study task. Write a function that returns an independent counter. Create two counters and use a scope diagram to explain why changing one does not change the other.
Data Structures: Objects and Arrays
Arrays and objects organise related data, while properties and methods provide ways to inspect and transform them. The were-squirrel journal example connects representation to analysis: observations become records whose features can be compared with an outcome. Mutability requires special care because two bindings can refer to the same object. The chapter also develops useful array and string operations, destructuring, JSON and related language features. Track the difference between changing an existing structure and constructing a new one. A data representation is successful when it supports the questions and operations the program needs.
Study task. Represent a week of journal entries, calculate one association and test how mutating a shared array affects two bindings that refer to it.
Higher-Order Functions
Higher-order functions make patterns of computation explicit by accepting or returning functions. Filtering selects records, mapping transforms them, and reducing combines them into a result. The script dataset demonstrates how these operations can be composed for text-related analysis, including the complications of character codes and writing systems. The chapter’s deeper theme is abstraction: remove repeated mechanics while preserving the meaningful choices. A concise chain is useful only when its intermediate values and assumptions remain understandable. Compare the abstract version with a loop to see which details have been generalised.
Study task. Implement one dataset question with a loop and then with filter, map and reduce. Explain the type and meaning of each intermediate result.
The Secret Life of Objects
Objects support interfaces through methods, prototypes and classes. The chapter develops abstract data types, private state, polymorphism, symbols, iterators and inheritance, showing how different implementations can obey the same contract. A class is not a substitute for deciding which operations an abstraction should expose. Prototype lookup explains why a property may be available without being stored directly on an instance. Iteration protocols provide a concrete example of cooperation through a shared interface. Use inheritance selectively, evaluating whether it clarifies the model or couples components more tightly than necessary.
Study task. Create a small collection class with a documented public interface and an iterator. Test that client code can use it without accessing its internal representation.
Project: A Robot
The robot project models a village, parcels and delivery actions. Persistent state separates describing a new situation from mutating the old one, allowing robot strategies to be compared using the same simulation. Route-following and pathfinding demonstrate the gap between a legal action and an efficient policy. Read the project as a complete pipeline: represent the world, define transitions, run a strategy and evaluate performance. A single favourable run is not a fair comparison. The project also reinforces the value of keeping simulation mechanics separate from decision-making code.
Study task. Compare two robot strategies over the same generated tasks. Record average turns and inspect a case in which the apparently smarter strategy performs worse.
Bugs and Errors
Bugs and errors are approached through stricter language use, testing, debugging and explicit exception handling. The chapter distinguishes failures caused by incorrect code from conditions a program may reasonably encounter while operating. Exceptions separate normal execution from an exceptional path, but catching too broadly can conceal genuine defects. Cleaning up after a failure and preserving useful diagnostic information are part of robust design. Assertions express assumptions that should hold internally. Develop a habit of reducing a bug to a small reproducible example before changing unrelated parts of the program.
Study task. Introduce one programming defect and one expected input failure into a small program. Handle them differently and justify where an exception should propagate.
Regular Expressions
Regular expressions describe patterns for recognising and transforming text. Character sets, repetition, groups, boundaries and alternatives build increasingly powerful matches, while backtracking explains surprising performance or results. Replacement and search methods connect patterns to practical parsing tasks such as reading an INI file. Greedy matching, dynamic construction and the state of a reusable expression require careful testing. Text also contains characters whose representation is more complex than a single code unit. Treat a pattern as a program with edge cases, not as an opaque string copied until it appears to work.
Study task. Create a parser for a small configuration format and test empty values, comments, malformed lines and Unicode text. Explain one case where a simpler string operation is preferable.
Modules
Modules organise programs into components with explicit dependencies and interfaces. ES modules and CommonJS illustrate different loading and export conventions; packages and build tools extend this organisation beyond one file. The important design decision is what a component promises to provide and what implementation details it can keep private. Excessive coupling makes a change spread across the system, while a useful boundary permits independent reasoning. Distinguish the language’s module mechanism from the package manager and bundler surrounding it. They solve related but different problems.
Study task. Split an earlier exercise into three modules. Draw the dependency relationships and remove one unnecessary export without breaking the public interface.
Asynchronous Programming
Asynchronous programming handles work that completes later without stopping all other activity. Callbacks, promises and async functions express dependencies, while failure can travel through promise chains or awaited operations. The chapter connects these tools to the event loop, generators and examples involving distributed information. Distinguish starting several operations from awaiting them one at a time. Shared state can become inconsistent even in a single-threaded environment when operations interleave around asynchronous boundaries. Reason about the ordering guarantees your code actually provides, not the order in which its lines appear.
Study task. Fetch three independent values concurrently, combine them and handle one failure. Compare this with sequential awaiting and trace a shared-state race.
Project: A Programming Language
The Egg project implements a small programming language with a parser, evaluator, environments and special forms. Parsing converts text into structured expressions; evaluation assigns meaning to those structures. Special forms differ from ordinary functions because they control which arguments are evaluated and when. Lexical environments connect the implementation back to scope and closures in JavaScript itself. Building an interpreter makes language design tangible: a short syntax requires explicit decisions about bindings, conditionals, functions and errors. Keep the parsing and evaluation stages separate when debugging.
Study task. Add one well-defined feature to Egg. Test valid syntax, malformed syntax and the way the feature interacts with an outer lexical scope.
JavaScript and the Browser
The browser chapter introduces the networked environment in which client-side JavaScript runs. HTML describes document structure, and scripts interact with a browser that enforces boundaries around access and execution. The relationship between the Internet, the Web and a page’s embedded resources clarifies what happens when a document loads. Compatibility also has a historical dimension: standards and implementations developed together rather than arriving as one fixed platform. Understanding the environment prepares readers to distinguish language behaviour from browser-specific APIs and security restrictions.
Study task. Create a minimal HTML page with an external script. Trace the requests and identify which features come from JavaScript and which are supplied by the browser.
The Document Object Model
The Document Object Model represents a page as a tree of nodes that programs can inspect and change. Traversal, selectors, attributes and node creation connect document structure to dynamic interfaces. Layout and styling add another layer: changing a style property can affect geometry as well as appearance. Avoid confusing the original HTML text with the current live tree, which scripts may already have altered. The chapter encourages building interfaces through explicit operations on nodes while keeping the document’s hierarchy understandable.
Study task. Build a table from an array of objects using DOM operations. Change one record and update the relevant node without rebuilding the entire page.
Handling Events
Events connect user activity and browser behaviour to program logic. Handlers receive event objects, propagation determines how listeners along a node hierarchy participate, and default actions may need deliberate handling. Keyboard, pointer, focus, scroll and load events have different meanings and timing. Timers and debouncing help manage repeated work, but the event loop still governs when callbacks run. Keep state changes explicit so that an interface responds consistently when events arrive in an unexpected order. A handler should do the work needed for one interaction without freezing the whole page.
Study task. Build a nested clickable interface and log event propagation. Add keyboard support and debounce an expensive input response while preserving the latest value.
Project: A Platform Game
The platform-game project combines level descriptions, actors, animation, keyboard input and collision rules. Its design separates game state from display, allowing motion and interactions to be reasoned about independently of DOM rendering. Time steps matter: movement depends on elapsed time rather than an assumed constant number of frames. Collision detection determines which transitions are legal, and actor updates produce the next state. Trace one frame before making broad changes. The project’s value lies in integrating earlier abstractions into a program whose behaviour can be observed continuously.
Study task. Add one game mechanic and describe its state transition before coding. Test collisions at corners and behaviour when a frame takes longer than expected.
Drawing on Canvas
Canvas provides an immediate drawing interface, contrasted with structured graphics such as SVG and the DOM. Paths, text, images and transformations enable richer rendering, while saved drawing state helps prevent one operation from accidentally affecting the next. The chapter returns to the platform game to demonstrate another display implementation. Choosing a graphics interface depends on what the application must select, animate, redraw or retain. A drawing command changes pixels; it does not automatically create an independently addressable document element.
Study task. Render the same simple scene with canvas and SVG. Apply a transformation, restore the drawing state and explain which interface better supports editing individual shapes.
HTTP and Forms
HTTP connects browser applications to remote resources through requests, responses, methods, headers and status codes. Fetch exposes this interaction to JavaScript, while forms provide structured input through controls with different behaviours. The chapter also covers browser security boundaries, HTTPS, file fields and client-side storage. Distinguish transport success from application success: receiving a response does not mean the requested operation succeeded. Validate input in the appropriate place and think about what information persists locally or crosses the network.
Study task. Build a form that submits structured data with fetch. Display loading, successful and failed states, and explain why server-side validation is still necessary.
Project: A Pixel Art Editor
The pixel-art editor develops an application around explicit state, reusable components and drawing tools. Separating the picture from its visual representation makes actions such as loading, saving and undo easier to reason about. Components receive data and dispatch changes rather than silently editing unrelated state. Undo history adds another design question: which actions belong in one recoverable step? The project shows that interface complexity often comes from coordinating many small interactions, not from one difficult algorithm. Keep the transition from an action to a new picture observable.
Study task. Add a drawing tool and an undoable operation. Test switching tools, loading an image and undoing several actions without corrupting the previous picture.
Node.js
Node.js provides a JavaScript environment outside the browser, with modules for filesystem access, HTTP services and streams. The chapter introduces running programs, installing packages and building a file server. Streams make it possible to process data incrementally rather than collecting everything in memory. Server code must also handle errors and validate the relationship between requested paths and permitted resources. Distinguish language concepts shared with the browser from APIs and authority specific to the server environment. Run file experiments in a dedicated test directory.
Study task. Implement a small server in a temporary workspace. Test a missing file, an invalid request and a large response, documenting how each error reaches the client.
Project: Skill-Sharing Website
The skill-sharing website integrates an HTTP interface, server-side state and a browser client. Long polling supports updates without requiring users to reload the page, connecting asynchronous control flow to a practical multi-user application. The design must coordinate requests, validation, state changes and rendering while handling failures. Read the API before modifying either side: the client and server must agree on resource names, data formats and response behaviour. The final project demonstrates how earlier chapters combine into a system whose correctness depends on component boundaries as much as individual functions.
Study task. Run two clients and test a talk being created, changed and deleted. Simulate a failed request and verify that the interface recovers without showing stale data as current.
How to study this book
- Use the fourth-edition PDF and its matching examples. Type and run small experiments rather than copying complete solutions first.
- For each concept, predict the result, execute the program and explain the difference. Keep a notebook of mistaken mental models.
- Complete the robot, Egg, game, editor and website projects in stages. After each working stage, make one small extension with observable behaviour.
- Use browser developer tools for client chapters and a dedicated Node.js workspace for server chapters. Read errors and network responses before changing code.
Questions for reflection
- When does mutation simplify a design, and when does persistent state make comparison easier?
- How do closures, event handlers and asynchronous operations interact?
- Which interface boundary made the final project easier to test or change?
Source edition and coverage
This guide follows the complete twenty-one-chapter fourth edition available from the author’s official site. Its six project chapters are treated as substantial learning units; exercises and solution hints remain in the source book. These are original study explanations and learning tasks. Read the complete book at the official source.
This page provides book information and study material. Full-text access is provided by the original publisher or authorised source; a listing does not grant permission to republish the book.
Read our Library Access & Copyright policyExplore the contents
Check the chapters covered in this edition.
Visit the official source
See reading, preview or purchase options.
Save for later
Keep this textbook in your saved collection.
Reader ratings & reviews
Share your thoughts
Your review helps other students choose the right resources.









