The book "Eloquent JavaScript" by Marijn Haverbeke is a comprehensive guide to learning JavaScript, covering a wide range of topics from basic programming principles to advanced concepts and project implementations. Below are detailed notes on each chapter,
- On Programming: Discusses the importance of programming in the modern world.
- Why Language Matters: Explains how the choice of programming language impacts the development process.
- What is JavaScript?: Introduction to JavaScript as a versatile language used in web browsers and other environments.
- Code, and What to Do with It: Encourages active engagement with the code examples and exercises in the book.
- Overview of This Book: Provides a high-level summary of the book's structure and content.
- Typographic Conventions: Explains the formatting used to represent code and output in the book.
- Values: Basic units of data in JavaScript.
- Numbers: Numerical data types.
console.log(2 + 2); // 4
- Strings: Textual data.
console.log("Hello, world!"); // Hello, world!
- Unary Operators: Operators with a single operand.
console.log(typeof 4.5); // "number"
- Boolean Values: True or false values.
console.log(3 > 2); // true
- Empty Values:
null
andundefined
.let x; console.log(x); // undefined
- Automatic Type Conversion: Type coercion in JavaScript.
console.log("5" - 1); // 4
- Expressions and Statements: Building blocks of programs.
- Bindings: Variables in JavaScript.
let caught = 5 * 5; console.log(caught); // 25
- Binding Names: Rules for naming variables.
- The Environment: The collection of bindings and their values.
- Functions: Reusable pieces of code.
function square(x) { return x * x; } console.log(square(4)); // 16
- The console.log Function: Outputting values.
- Return Values: Values returned from functions.
- Control Flow: The order in which statements are executed.
- Conditional Execution: Using
if
statements.if (true) { console.log("This is true"); }
- while and do loops: Looping constructs.
let number = 0; while (number <= 12) { console.log(number); number = number + 2; }
- Defining a Function: Creating functions.
const makeNoise = function() { console.log("Pling!"); };
- Bindings and Scopes: Variable scope.
let x = 10; if (true) { let y = 20; var z = 30; } console.log(x + z); // 40
- Nested Scope: Functions within functions.
- Functions as Values: Assigning functions to variables.
let launchMissiles = function() { missileSystem.launch("now"); }; launchMissiles = function() {};
- Declaration Notation: Function declarations.
function future() { return "You'll never have flying cars"; }
- Arrow Functions: Concise function syntax.
const power = (base, exponent) => { let result = 1; for (let count = 0; count < exponent; count++) { result *= base; } return result; };
- The Call Stack: Understanding function execution.
- Optional Arguments: Functions with flexible parameters.
function power(base, exponent = 2) { let result = 1; for (let count = 0; count < exponent; count++) { result *= base; } return result; }
- The Weresquirrel: Introduction to objects and arrays through a fictional problem.
- Data Sets: Storing collections of values.
- Properties: Accessing object properties.
let anObject = {left: 1, right: 2}; console.log(anObject.left); // 1
- Methods: Functions as object properties.
let rabbit = {}; rabbit.speak = function(line) { console.log(`The rabbit says '${line}'`); }; rabbit.speak("I'm alive."); // The rabbit says 'I'm alive.'
- Objects: Creating and modifying objects.
- Mutability: Objects are mutable.
let object1 = {value: 10}; let object2 = object1; let object3 = {value: 10}; console.log(object1 == object2); // true console.log(object1 == object3); // false
- The Lycanthrope's Log: Using arrays to manage data.
- Computing Correlation: Analyzing data.
function phi(table) { return (table[3] * table[0] - table[2] * table[1]) / Math.sqrt((table[2] + table[3]) * (table[0] + table[1]) * (table[1] + table[3]) * (table[0] + table[2])); }
- Array Loops: Iterating over arrays.
let journal = []; function addEntry(events, squirrel) { journal.push({events, squirrel}); }
- Further Arrayology: Advanced array methods.
let todoList = []; function remember(task) { todoList.push(task); } function getTask() { return todoList.shift(); } function rememberUrgently(task) { todoList.unshift(task); }
- Abstraction: Simplifying code by abstracting repetitive patterns.
- Abstracting Repetition: Using functions to abstract repetition.
function repeat(n, action) { for (let i = 0; i < n; i++) { action(i); } } repeat(3, console.log);
- Higher-Order Functions: Functions that operate on other functions.
function greaterThan(n) { return m => m > n; } let greaterThan10 = greaterThan(10); console.log(greaterThan10(11)); // true
- Script Data Set: Working with data.
- Filtering Arrays: Using
filter
.function filter(array, test) { let passed = []; for (let element of array) { if (test(element)) { passed.push(element); } } return passed; } console.log(filter(SCRIPTS, script => script.living));
- Transforming with Map: Using
map
.function map(array, transform) { let mapped = []; for (let element of array) { mapped.push(transform(element)); } return mapped; }
- Summarizing with Reduce: Using
reduce
.function reduce(array, combine, start) { let current = start; for (let element of array) { current = combine(current, element); } return current; } console.log(reduce([1, 2, 3, 4], (a, b) => a + b, 0)); // 10
- Composability: Combining small functions to build complex operations.
- Strings and Character Codes: Handling strings and character codes.
- Recognizing Text: Using regular expressions to work with text.
- Abstract Data Types: Custom data structures.
- Methods: Functions as properties of objects.
- Prototypes: Inheritance in JavaScript.
let protoRabbit = { speak(line) { console.log(`The ${this.type} rabbit says '${line}'`); } }; let killerRabbit = Object.create(protoRabbit); killerRabbit.type = "killer"; killerRabbit.speak("SKREEEE!"); // The killer rabbit says 'SKREEEE!'
- Classes: Using the
class
keyword.class Rabbit { constructor(type) { this.type = type; } speak(line) { console.log(`The ${this.type} rabbit says '${line}'`); } } let killerRabbit = new Rabbit("killer");
- Private Properties: Encapsulation in JavaScript.
- **Overriding
Derived Properties**: Customizing inherited properties.
- Maps: Using
Map
for key-value pairs.let ages = new Map(); ages.set("Boris", 39); ages.set("Liang", 22); ages.set("Julia", 62); console.log(`Julia is ${ages.get("Julia")}`); // Julia is 62
- Meadowfield: A fictional scenario to build a robot simulation.
- The Task: Overview of the project's goal.
- The Village: Representing the village map.
const roads = [ "Alice's House-Bob's House", "Alice's House-Cabin", "Alice's House-Post Office", "Bob's House-Town Hall", "Daria's House-Ernie's House", "Daria's House-Town Hall", "Ernie's House-Grete's House", "Grete's House-Farm", "Grete's House-Shop", "Marketplace-Post Office", "Marketplace-Town Hall", "Marketplace-Shop", "Marketplace-Farm", "Marketplace-Julia's House", "Town Hall-Farm", "Town Hall-Shop", "Town Hall-Julia's House", "Julia's House-Farm" ];
- Persistent Group: Data structures for storing robot states.
- The Robot's Memory: Managing the robot's memory.
- Persistent Data: Working with immutable data structures.
- Language: Understanding errors in programming.
- Strict Mode: Enforcing stricter parsing and error handling in JavaScript.
"use strict";
- Types: Common error types in JavaScript.
- Testing: Writing tests for code.
- Debugging: Techniques for finding and fixing bugs.
function numberToString(n, base = 10) { let result = "", sign = ""; if (n < 0) { sign = "-"; n = -n; } do { result = String.fromCharCode(n % base + 48) + result; n = Math.floor(n / base); } while (n > 0); return sign + result; }
- Error Propagation: Handling errors gracefully.
- Assertions: Using assertions to validate assumptions in code.
- Creating a Regular Expression: Using
RegExp
constructor.let re1 = new RegExp("abc"); let re2 = /abc/;
- Testing for Matches: Checking if a pattern matches a string.
console.log(/abc/.test("abcde")); // true console.log(/abc/.test("abxde")); // false
- Sets of Characters: Using character classes.
console.log(/[0123456789]/.test("in 1992")); // true
- Repetitions: Quantifiers in regular expressions.
let dateTime = /\d\d-\d\d-\d\d\d\d \d\d:\d\d/; console.log(dateTime.test("01-30-2003 15:20")); // true
- Grouping Subexpressions: Capturing groups.
let cartoonCrying = /boo+(hoo+)+/i; console.log(cartoonCrying.test("Boohoooohoohooo")); // true
- Matches and Groups: Extracting matched substrings.
let match = /\d+/.exec("one two 100"); console.log(match); // ["100"] console.log(match.index); // 8
- Why Modules Help: Benefits of modular code.
- Packages: Managing dependencies with package managers.
- Evaluating Data as Code: Using
eval
.const x = 1; function evalAndReturnX(code) { eval(code); return x; } console.log(evalAndReturnX("var x = 2")); // 1
- CommonJS: Using CommonJS module system.
const { parse } = require("ini"); console.log(parse("x = 10\nk = 20")); // { x: "10", k: "20" }
- ES Modules: Using ES module system.
import { createRequire } from "module"; const require = createRequire(import.meta.url); const { parse } = require("ini"); console.log(parse("x = 10\nk = 20")); // { x: "10", k: "20" }
- Asynchronous Code: Understanding async programming.
- Callbacks: Using callbacks for async operations.
setTimeout(() => console.log("Tick"), 500);
- Promises: Using promises for better async handling.
let fifteen = Promise.resolve(15); fifteen.then(value => console.log(`Got ${value}`)); // Got 15
- Async Functions: Using
async
andawait
.async function f() { let result = await Promise.resolve(15); console.log(result); // 15 } f();
- Generators: Using generator functions.
function* powers(n) { for (let current = n; ; current *= n) { yield current; } } for (let power of powers(3)) { if (power > 50) break; console.log(power); // 3, 9, 27 }
- Parsing: Building a parser for a simple language.
function parseExpression(program) { program = skipSpace(program); let match, expr; if (match = /^"([^"]*)"/.exec(program)) { expr = { type: "value", value: match[1] }; } else if (match = /^\d+\b/.exec(program)) { expr = { type: "value", value: Number(match[0]) }; } else if (match = /^[^\s(),"]+/.exec(program)) { expr = { type: "word", name: match[0] }; } else { throw new SyntaxError("Unexpected syntax: " + program); } return parseApply(expr, program.slice(match[0].length)); }
- The Evaluator: Building an evaluator for the language.
function evaluate(expr, scope) { if (expr.type == "value") { return expr.value; } else if (expr.type == "word") { if (expr.name in scope) { return scope[expr.name]; } else { throw new ReferenceError(`Undefined binding: ${expr.name}`); } } else if (expr.type == "apply") { let { operator, args } = expr; if (operator.type == "word" && operator.name in specialForms) { return specialForms[operator.name](expr.args, scope); } else { let op = evaluate(operator, scope); if (typeof op == "function") { return op(...args.map(arg => evaluate(arg, scope))); } else { throw new TypeError("Applying a non-function."); } } } }
- The Document Object Model: Manipulating the DOM.
- DOM Nodes: Working with DOM nodes.
document.body.appendChild(document.createTextNode("hello world"));
- Attributes: Setting attributes on elements.
let link = document.querySelector("a"); console.log(link.href); // Outputs the href attribute value
- Events: Handling user interactions.
let button = document.querySelector("button"); button.addEventListener("click", () => { console.log("Button clicked"); });
- Layout: Understanding CSS and layout.
- The Canvas Element: Drawing on a canvas.
let canvas = document.querySelector("canvas"); let context = canvas.getContext("2d"); context.fillStyle = "red"; context.fillRect(10, 10, 100, 50);
- Nodes: Understanding the DOM node hierarchy.
- Tree Structure: Navigating the DOM tree.
- Attributes: Manipulating element attributes.
let paras = document.body.getElementsByTagName("p"); console.log(paras[0].getAttribute("class")); // Outputs the class attribute value
- Finding Elements: Using selectors to find elements.
let link = document.querySelector("a[href='http://example.com']"); console.log(link.href); // http://example.com
- Changing the Document: Adding and removing nodes.
let newParagraph = document.createElement("p"); newParagraph.textContent =
"This is a new paragraph."; document.body.appendChild(newParagraph);
### Chapter 15: Handling Events
- **Events**: Understanding event-driven programming.
- **Event Handlers**: Attaching handlers to events.
```javascript
button.addEventListener("click", () => {
console.log("Button clicked");
});
- Propagation: Understanding event propagation.
document.body.addEventListener("click", event => { console.log("Body clicked"); }, true); // true means capture phase
- Default Actions: Preventing default actions.
let link = document.querySelector("a"); link.addEventListener("click", event => { event.preventDefault(); console.log("Link clicked"); });
- Game Plan: Overview of the game project.
- The Game World: Representing the game world.
const simpleLevelPlan = ` ...................... ..#................#.. ..#..............=.#.. ..#.........o.o....#.. ..#.@......#####...#.. ..#####............#.. ......#++++++++++++#.. ......##############.. ......................`;
- Actors: Implementing the game actors.
- Drawing: Drawing the game on the screen.
function drawGrid(level) { return elt("table", { class: "background", style: `width: ${level.width * scale}px` }, ...level.rows.map(row => elt("tr", { style: `height: ${scale}px` }, ...row.map(type => elt("td", { class: type }))) )); }
- Collision and Interaction: Handling collisions and interactions.
- Levels: Building and loading game levels.
- Game Over: Detecting game over conditions.
- The Canvas Element: Introduction to canvas.
let canvas = document.querySelector("canvas"); let context = canvas.getContext("2d");
- Shapes: Drawing shapes on canvas.
context.fillStyle = "blue"; context.fillRect(10, 10, 100, 50);
- Paths: Drawing complex shapes.
context.beginPath(); context.moveTo(50, 50); context.lineTo(150, 50); context.lineTo(100, 100); context.closePath(); context.stroke();
- Text: Drawing text on canvas.
context.font = "30px Arial"; context.fillText("Hello, world!", 10, 50);
- Images: Drawing images on canvas.
let img = new Image(); img.src = "example.png"; img.onload = () => { context.drawImage(img, 10, 10); };
- Forms and Form Fields: Handling user input via forms.
- HTTP: Understanding HTTP requests and responses.
- Fetching Data: Using
fetch
to get data.fetch("https://api.example.com/data") .then(response => response.json()) .then(data => console.log(data));
- Sending Data: Sending data via HTTP.
fetch("https://api.example.com/data", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: "John" }) }) .then(response => response.json()) .then(data => console.log(data));
- The Editor: Overview of the pixel art editor project.
- Drawing Tools: Implementing drawing tools.
- Color Picker: Creating a color picker.
- Saving and Loading: Handling save and load functionality.
- Setting Up a Node Environment: Installing Node.js.
- Modules: Using modules in Node.js.
- File System: Working with the file system.
const fs = require("fs"); fs.readFile("file.txt", "utf8", (err, data) => { if (err) throw err; console.log(data); });
- HTTP Servers: Creating HTTP servers.
const http = require("http"); const server = http.createServer((req, res) => { res.writeHead(200, { "Content-Type": "text/plain" }); res.end("Hello, world!"); }); server.listen(8000);
- Code Editors: Choosing a code editor.
- Linting: Using linters to catch errors.
- Version Control: Using version control systems like Git.
- Package Managers: Managing dependencies with package managers.
- JavaScript Syntax: Detailed syntax reference.
- Built-in Functions: Overview of built-in JavaScript functions.
- Standard Objects: Overview of standard JavaScript objects.
- ES6 and Beyond: New features in modern JavaScript versions.
- Booleans: Logical operations.
console.log(true && false); // false console.log(true || false); // true console.log(!true); // false
-
Control Flow: If, else, while, do while, for.
if (true) { console.log("This is true"); } else { console.log("This is false"); } let count = 0; while (count < 5) { console.log(count); count++; } do { console.log(count); count--; } while (count > 0); for (let i = 0; i < 5; i++) { console.log(i); }
-
Functions: Defining and calling functions.
function sayHello(name) { console.log("Hello, " + name); } sayHello("World");
-
Arrays: Basic array operations.
let list = [1, 2, 3, 4, 5]; console.log(list[0]); // 1 list.push(6); console.log(list); // [1, 2, 3, 4, 5, 6]
-
Objects: Creating and manipulating objects.
let person = { name: "Alice", age: 30 }; console.log(person.name); // Alice person.age = 31; console.log(person.age); // 31
-
Higher-Order Functions: Functions that operate on functions.
function repeat(n, action) { for (let i = 0; i < n; i++) { action(i); } } repeat(3, console.log); // 0 1 2
-
Filter: Filtering arrays.
let numbers = [1, 2, 3, 4, 5]; let evens = numbers.filter(n => n % 2 === 0); console.log(evens); // [2, 4]
-
Map: Mapping over arrays.
let doubled = numbers.map(n => n * 2); console.log(doubled); // [2, 4, 6, 8, 10]
-
Reduce: Reducing arrays to a single value.
let sum = numbers.reduce((a, b) => a + b, 0); console.log(sum); // 15
-
Methods: Adding methods to objects.
let rabbit = {}; rabbit.speak = function(line) { console.log(`The rabbit says '${line}'`); }; rabbit.speak("Hello!"); // The rabbit says 'Hello B25D !'
-
Prototypes: Using prototypes for inheritance.
let protoRabbit = { speak(line) { console.log(`The rabbit says '${line}'`); } }; let killerRabbit = Object.create(protoRabbit); killerRabbit.speak("I am a killer!"); // The rabbit says 'I am a killer!'
- Replacing with Regular Expressions: Replacing text using regex.
let text = "Borobudur"; let replaced = text.replace(/[ou]/g, "a"); console.log(replaced); // Barabadar
- Styling: Changing element styles.
let paragraph = document.querySelector("p"); paragraph.style.color = "blue";
- Creating Elements: Creating new DOM elements.
let newDiv = document.createElement("div"); newDiv.textContent = "Hello, DOM!"; document.body.appendChild(newDiv);
- Event Listeners: Attaching multiple event listeners.
let button = document.querySelector("button"); button.addEventListener("click", () => { console.log("Button was clicked!"); }); button.addEventListener("mouseover", () => { console.log("Mouse over the button!"); });
- Actor Classes: Defining classes for game actors.
class Player { constructor(pos, speed) { this.pos = pos; this.speed = speed; } } class Coin { constructor(pos) { this.pos = pos; } }
- Basic Drawing: Implementing basic drawing functionality.
function drawPixel(x, y, color) { let canvas = document.querySelector("canvas"); let ctx = canvas.getContext("2d"); ctx.fillStyle = color; ctx.fillRect(x, y, 1, 1); } canvas.addEventListener("click", event => { let x = event.offsetX; let y = event.offsetY; drawPixel(x, y, "black"); });
- Git Commands: Basic Git commands.
# Initialize a new Git repository git init # Add files to staging area git add . # Commit changes git commit -m "Initial commit" # Check status git status
-
Template Literals: Using template literals.
let name = "Alice"; let greeting = `Hello, ${name}!`; console.log(greeting); // Hello, Alice!
-
Destructuring: Destructuring arrays and objects.
let [x, y] = [1, 2]; console.log(x, y); // 1 2 let { name, age } = { name: "Alice", age: 30 }; console.log(name, age); // Alice 30
This completes the detailed notes with code examples for all topics in "Eloquent JavaScript." For more comprehensive explanations and additional examples, refer to the book itself. These notes provide a broad overview of the topics covered in "Eloquent JavaScript." For detailed explanations and additional code examples, refer to the book itself.